mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-08 00:05:09 -04:00
Mesh export processes, first part : infrastructure and export vertices (#39664)
[processing] Infrastructure for QgsMeshLayer to add processing algorithms, dataset group paramater and dataset time parameter to allow the user to easily choose a dataset.
This commit is contained in:
parent
a1fcc7da4a
commit
1fbba79a0f
@ -257,7 +257,7 @@ Returns the extra dataset groups count handle by the layer
|
||||
|
||||
QList<int> datasetGroupsIndexes() const;
|
||||
%Docstring
|
||||
Returns the list of indexes of dataset groups count handled by the layer
|
||||
Returns the list of indexes of dataset groups handled by the layer
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -173,6 +173,24 @@ If not explicitly set, the unit will default to the :py:func:`~QgsProcessingCont
|
||||
.. seealso:: :py:func:`setDistanceUnit`
|
||||
|
||||
.. versionadded:: 3.16
|
||||
%End
|
||||
|
||||
QgsDateTimeRange currentTimeRange() const;
|
||||
%Docstring
|
||||
Returns the current time range to use for temporal operations.
|
||||
|
||||
.. seealso:: :py:func:`setCurrentTimeRange`
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
void setCurrentTimeRange( const QgsDateTimeRange ¤tTimeRange );
|
||||
%Docstring
|
||||
Sets the ``current`` time range to use for temporal operations.
|
||||
|
||||
.. seealso:: :py:func:`currentTimeRange`
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
QgsMapLayerStore *temporaryLayerStore();
|
||||
|
@ -0,0 +1,180 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/processing/qgsprocessingparametermeshdataset.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
class QgsProcessingParameterMeshDatasetGroups : QgsProcessingParameterDefinition
|
||||
{
|
||||
%Docstring
|
||||
A parameter for processing algorithms that need a list of mesh dataset groups
|
||||
A valid value for this parameter is a list (QVariantList) of dataset groups index in the mesh layer scope
|
||||
Dataset group index can be evaluated with the method :py:func:`~valueAsDatasetGroup`
|
||||
|
||||
.. note::
|
||||
|
||||
This parameter is dependent on a mesh layer parameter (see QgsProcessingParameterMeshLayer)
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsprocessingparametermeshdataset.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsProcessingParameterMeshDatasetGroups( const QString &name,
|
||||
const QString &description = QString(),
|
||||
const QString &meshLayerParameterName = QString(),
|
||||
QgsMeshDatasetGroupMetadata::DataType dataType = QgsMeshDatasetGroupMetadata::DataOnVertices,
|
||||
bool optional = false );
|
||||
%Docstring
|
||||
Constructor
|
||||
|
||||
:param name: name of the parameter
|
||||
:param description: description of the parameter
|
||||
:param meshLayerParameterName: name of the associated mesh layer parameter
|
||||
:param dataType: data type supported by the parameter
|
||||
:param optional: whether the parameter is optional
|
||||
%End
|
||||
|
||||
virtual QgsProcessingParameterDefinition *clone() const /Factory/;
|
||||
|
||||
virtual QString type() const;
|
||||
|
||||
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
|
||||
|
||||
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
|
||||
|
||||
virtual QString asPythonString( QgsProcessing::PythonOutputType outputType = QgsProcessing::PythonQgsProcessingAlgorithmSubclass ) const;
|
||||
|
||||
virtual QStringList dependsOnOtherParameters() const;
|
||||
|
||||
|
||||
static QString typeName();
|
||||
%Docstring
|
||||
Returns the type name for the parameter class.
|
||||
%End
|
||||
|
||||
QString meshLayerParameterName() const;
|
||||
%Docstring
|
||||
Returns the name of the mesh layer parameter
|
||||
%End
|
||||
|
||||
QgsMeshDatasetGroupMetadata::DataType dataType() const;
|
||||
%Docstring
|
||||
Returns the data type supported by the parameter
|
||||
%End
|
||||
|
||||
static QList<int> valueAsDatasetGroup( const QVariant &value );
|
||||
%Docstring
|
||||
Returns the ``value`` as a list if dataset group indexes
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
class QgsProcessingParameterMeshDatasetTime : QgsProcessingParameterDefinition
|
||||
{
|
||||
%Docstring
|
||||
A parameter for processing algorithms that need a list of mesh dataset index from time parameter
|
||||
A valid value for this parameter is a map (QVariantMap) with in this form:
|
||||
|
||||
- "type" : the type of time settings "current-context-time", "defined-date-time", "dataset-time-step" or "none" if all the dataset groups are static
|
||||
- "value" : nothing if type is "static" or "current-context-time", QDateTime if "defined-date-time" or, for "dataset_time_step", list of two int representing the dataset index that is the reference for the time step
|
||||
|
||||
.. note::
|
||||
|
||||
This parameter is dependent on a mesh layer parameter (:py:class:`QgsProcessingParameterMeshLayer`)
|
||||
and on mesh datast group parameter (:py:class:`QgsProcessingParameterMeshDatasetGroups`)
|
||||
|
||||
.. versionadded:: 3.18
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsprocessingparametermeshdataset.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsProcessingParameterMeshDatasetTime(
|
||||
const QString &name,
|
||||
const QString &description = QString(),
|
||||
const QString &meshLayerParameterName = QString(),
|
||||
const QString &datasetGroupParameterName = QString() );
|
||||
%Docstring
|
||||
Constructor
|
||||
|
||||
:param name: name of the parameter
|
||||
:param description: description of the parameter
|
||||
:param meshLayerParameterName: name of the associated mesh layer parameter (:py:class:`QgsProcessingParameterMeshLayer`)
|
||||
:param datasetGroupParameterName: name of the associated dataset group parameter (:py:class:`QgsProcessingParameterMeshDatasetGroups`)
|
||||
%End
|
||||
|
||||
virtual QgsProcessingParameterDefinition *clone() const /Factory/;
|
||||
|
||||
virtual QString type() const;
|
||||
|
||||
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
|
||||
|
||||
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
|
||||
|
||||
virtual QString asPythonString( QgsProcessing::PythonOutputType outputType = QgsProcessing::PythonQgsProcessingAlgorithmSubclass ) const;
|
||||
|
||||
virtual QStringList dependsOnOtherParameters() const;
|
||||
|
||||
|
||||
static QString typeName();
|
||||
%Docstring
|
||||
Returns the type name for the parameter class.
|
||||
%End
|
||||
|
||||
QString meshLayerParameterName() const;
|
||||
%Docstring
|
||||
Returns the name of the mesh layer parameter
|
||||
%End
|
||||
|
||||
QString datasetGroupParameterName() const;
|
||||
%Docstring
|
||||
Returns the name of the dataset groups parameter
|
||||
%End
|
||||
|
||||
static QString valueAsTimeType( const QVariant &value );
|
||||
%Docstring
|
||||
Returns the ``dataset`` value time type as a string :
|
||||
current-context-time : the time is store in the processing context (e.g. current canvas time), in this case the value does not contain any time value
|
||||
defined-date-time : absolute time of type QDateTime
|
||||
dataset-time-step : a time step of existing dataset, in this case the time takes the form of a QMeshDatasetIndex with value to the corresponding dataset index
|
||||
static : dataset groups are all static, in this case the value does not contain any time value
|
||||
%End
|
||||
|
||||
static QgsMeshDatasetIndex timeValueAsDatasetIndex( const QVariant &value );
|
||||
%Docstring
|
||||
Returns the ``value`` as a QgsMeshDatasetIndex if the value has "dataset-time-step" type.
|
||||
If the value has the wrong type return an invalid dataset index
|
||||
|
||||
.. seealso:: :py:func:`valueAsTimeType`
|
||||
%End
|
||||
|
||||
static QDateTime timeValueAsDefinedDateTime( const QVariant &value );
|
||||
%Docstring
|
||||
Returns the ``value`` as a QDateTime if the value has "defined-date-time" type.
|
||||
If the value has the wrong type return an invalid QDatetime
|
||||
|
||||
.. seealso:: :py:func:`valueAsTimeType`
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/processing/qgsprocessingparametermeshdataset.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -230,6 +230,7 @@ their acceptable ranges, defaults, etc.
|
||||
#include "qgsprocessingparameterfieldmap.h"
|
||||
#include "qgsprocessingparametertininputlayers.h"
|
||||
#include "qgsprocessingparametervectortilewriterlayers.h"
|
||||
#include "qgsprocessingparametermeshdataset.h"
|
||||
%End
|
||||
%ConvertToSubClassCode
|
||||
if ( sipCpp->type() == QgsProcessingParameterBoolean::typeName() )
|
||||
@ -314,6 +315,10 @@ their acceptable ranges, defaults, etc.
|
||||
sipType = sipType_QgsProcessingParameterVectorTileWriterLayers;
|
||||
else if ( sipCpp->type() == QgsProcessingParameterDxfLayers::typeName() )
|
||||
sipType = sipType_QgsProcessingParameterDxfLayers;
|
||||
else if ( sipCpp->type() == QgsProcessingParameterMeshDatasetGroups::typeName() )
|
||||
sipType = sipType_QgsProcessingParameterMeshDatasetGroups;
|
||||
else if ( sipCpp->type() == QgsProcessingParameterMeshDatasetTime::typeName() )
|
||||
sipType = sipType_QgsProcessingParameterMeshDatasetTime;
|
||||
else
|
||||
sipType = nullptr;
|
||||
%End
|
||||
|
@ -477,6 +477,7 @@
|
||||
%Include auto_generated/processing/qgsprocessingparameteraggregate.sip
|
||||
%Include auto_generated/processing/qgsprocessingparameterdxflayers.sip
|
||||
%Include auto_generated/processing/qgsprocessingparameterfieldmap.sip
|
||||
%Include auto_generated/processing/qgsprocessingparametermeshdataset.sip
|
||||
%Include auto_generated/processing/qgsprocessingparameters.sip
|
||||
%Include auto_generated/processing/qgsprocessingparametertininputlayers.sip
|
||||
%Include auto_generated/processing/qgsprocessingparametertype.sip
|
||||
|
@ -76,6 +76,9 @@ def createContext(feedback=None):
|
||||
|
||||
context.setExpressionContext(createExpressionContext())
|
||||
|
||||
if iface and iface.mapCanvas() and iface.mapCanvas().mapSettings().isTemporal():
|
||||
context.setCurrentTimeRange(iface.mapCanvas().mapSettings().temporalRange())
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
@ -61,6 +61,7 @@ SET(QGIS_ANALYSIS_SRCS
|
||||
processing/qgsalgorithmexecutespatialitequeryregistered.cpp
|
||||
processing/qgsalgorithmexplode.cpp
|
||||
processing/qgsalgorithmexplodehstore.cpp
|
||||
processing/qgsalgorithmexportmeshvertices.cpp
|
||||
processing/qgsalgorithmextendlines.cpp
|
||||
processing/qgsalgorithmextentfromlayer.cpp
|
||||
processing/qgsalgorithmextenttolayer.cpp
|
||||
|
291
src/analysis/processing/qgsalgorithmexportmeshvertices.cpp
Normal file
291
src/analysis/processing/qgsalgorithmexportmeshvertices.cpp
Normal file
@ -0,0 +1,291 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmtinmeshcreation.h
|
||||
---------------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Vincent Cloarec
|
||||
email : vcloarec at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsalgorithmexportmeshvertices.h"
|
||||
#include "qgsprocessingparametermeshdataset.h"
|
||||
#include "qgsmeshdataset.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgsmeshlayerutils.h"
|
||||
#include "qgsmeshlayertemporalproperties.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
QString QgsExportMeshVerticesAlgorithm::group() const
|
||||
{
|
||||
return QObject::tr( "Mesh" );
|
||||
}
|
||||
|
||||
QString QgsExportMeshVerticesAlgorithm::groupId() const
|
||||
{
|
||||
return QStringLiteral( "mesh" );
|
||||
}
|
||||
|
||||
QString QgsExportMeshVerticesAlgorithm::shortHelpString() const
|
||||
{
|
||||
return QObject::tr( "Exports a mesh layer's vertices to a point vector layer, with the dataset values on vertices as attribute values" );
|
||||
}
|
||||
|
||||
QString QgsExportMeshVerticesAlgorithm::name() const
|
||||
{
|
||||
return QStringLiteral( "exportmeshvertices" );
|
||||
}
|
||||
|
||||
QString QgsExportMeshVerticesAlgorithm::displayName() const
|
||||
{
|
||||
return QObject::tr( "Export mesh vertices" );
|
||||
}
|
||||
|
||||
QgsProcessingAlgorithm *QgsExportMeshVerticesAlgorithm::createInstance() const
|
||||
{
|
||||
return new QgsExportMeshVerticesAlgorithm();
|
||||
}
|
||||
|
||||
void QgsExportMeshVerticesAlgorithm::initAlgorithm( const QVariantMap &configuration )
|
||||
{
|
||||
Q_UNUSED( configuration );
|
||||
|
||||
addParameter( new QgsProcessingParameterMeshLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input Mesh Layer" ) ) );
|
||||
|
||||
|
||||
addParameter( new QgsProcessingParameterMeshDatasetGroups(
|
||||
QStringLiteral( "DATASET_GROUPS" ),
|
||||
QObject::tr( "Dataset groups" ),
|
||||
QStringLiteral( "INPUT" ),
|
||||
QgsMeshDatasetGroupMetadata::DataOnVertices ) );
|
||||
|
||||
addParameter( new QgsProcessingParameterMeshDatasetTime(
|
||||
QStringLiteral( "DATASET_TIME" ),
|
||||
QObject::tr( "Dataset time" ),
|
||||
QStringLiteral( "INPUT" ),
|
||||
QStringLiteral( "DATASET_GROUPS" ) ) );
|
||||
|
||||
addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS_OUTPUT" ), QObject::tr( "Output coordinate system" ), QVariant(), true ) );
|
||||
|
||||
QStringList exportVectorOptions;
|
||||
exportVectorOptions << QObject::tr( "Cartesian (x,y)" )
|
||||
<< QObject::tr( "Polar (magnitude,degree)" )
|
||||
<< QObject::tr( "Cartesian and Polar" );
|
||||
addParameter( new QgsProcessingParameterEnum( QStringLiteral( "VECTOR_OPTION" ), QObject::tr( "Export vector option" ), exportVectorOptions, false, 0 ) );
|
||||
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Output vector layer" ), QgsProcessing::TypeVectorPoint ) );
|
||||
}
|
||||
|
||||
static QVector<double> vectorValue( const QgsMeshDatasetValue &value, int exportOption )
|
||||
{
|
||||
QVector<double> ret( exportOption == 2 ? 4 : 2 );
|
||||
|
||||
if ( exportOption == 0 || exportOption == 2 )
|
||||
{
|
||||
ret[0] = value.x();
|
||||
ret[1] = value.y();
|
||||
}
|
||||
if ( exportOption == 1 || exportOption == 2 )
|
||||
{
|
||||
double x = value.x();
|
||||
double y = value.y();
|
||||
double magnitude = sqrt( x * x + y * y );
|
||||
double direction = ( asin( x / magnitude ) ) / M_PI * 180;
|
||||
if ( y < 0 )
|
||||
direction = 180 - direction;
|
||||
|
||||
if ( exportOption == 1 )
|
||||
{
|
||||
ret[0] = magnitude;
|
||||
ret[1] = direction;
|
||||
}
|
||||
if ( exportOption == 2 )
|
||||
{
|
||||
ret[2] = magnitude;
|
||||
ret[3] = direction;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool QgsExportMeshVerticesAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral( "INPUT" ), context );
|
||||
|
||||
if ( !meshLayer || !meshLayer->isValid() )
|
||||
return false;
|
||||
|
||||
QgsCoordinateReferenceSystem outputCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
|
||||
mTransform = QgsCoordinateTransform( meshLayer->crs(), outputCrs, context.transformContext() );
|
||||
if ( !meshLayer->nativeMesh() )
|
||||
meshLayer->updateTriangularMesh( mTransform ); //necessary to load the native mesh
|
||||
|
||||
mNativeMesh = *meshLayer->nativeMesh();
|
||||
|
||||
QList<int> datasetGroups =
|
||||
QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( parameters.value( QStringLiteral( "DATASET_GROUPS" ) ) );
|
||||
|
||||
if ( feedback )
|
||||
{
|
||||
feedback->setProgressText( QObject::tr( "Preparing data" ) );
|
||||
}
|
||||
|
||||
QDateTime layerReferenceTime = static_cast<QgsMeshLayerTemporalProperties *>( meshLayer->temporalProperties() )->referenceTime();
|
||||
|
||||
//! Extract the date time used to export dataset values under a relative time
|
||||
QgsInterval relativeTime( 0 );
|
||||
QVariant parameterTimeVariant = parameters.value( QStringLiteral( "DATASET_TIME" ) );
|
||||
|
||||
QString timeType = QgsProcessingParameterMeshDatasetTime::valueAsTimeType( parameterTimeVariant );
|
||||
|
||||
if ( timeType == QStringLiteral( "dataset-time-step" ) )
|
||||
{
|
||||
QgsMeshDatasetIndex datasetIndex = QgsProcessingParameterMeshDatasetTime::timeValueAsDatasetIndex( parameterTimeVariant );
|
||||
relativeTime = meshLayer->datasetRelativeTime( datasetIndex );
|
||||
}
|
||||
else if ( timeType == QStringLiteral( "defined-date-time" ) )
|
||||
{
|
||||
QDateTime dateTime = QgsProcessingParameterMeshDatasetTime::timeValueAsDefinedDateTime( parameterTimeVariant );
|
||||
if ( dateTime.isValid() )
|
||||
relativeTime = QgsInterval( layerReferenceTime.secsTo( dateTime ) );
|
||||
}
|
||||
else if ( timeType == QStringLiteral( "current-context-time" ) )
|
||||
{
|
||||
QDateTime dateTime = context.currentTimeRange().begin();
|
||||
if ( dateTime.isValid() )
|
||||
relativeTime = QgsInterval( layerReferenceTime.secsTo( dateTime ) );
|
||||
}
|
||||
|
||||
for ( int i = 0; i < datasetGroups.count(); ++i )
|
||||
{
|
||||
int groupIndex = datasetGroups.at( i );
|
||||
QgsMeshDatasetIndex datasetIndex = meshLayer->datasetIndexAtRelativeTime( relativeTime, groupIndex );
|
||||
|
||||
DataGroup dataGroup;
|
||||
dataGroup.metadata = meshLayer->datasetGroupMetadata( datasetIndex );
|
||||
int dataCount = dataGroup.metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices ? mNativeMesh.vertexCount() : mNativeMesh.faceCount();
|
||||
dataGroup.datasetValues = meshLayer->datasetValues( datasetIndex, 0, dataCount );
|
||||
dataGroup.activeFaceFlagValues = meshLayer->areFacesActive( datasetIndex, 0, mNativeMesh.faceCount() );
|
||||
|
||||
mDataPerGroup.append( dataGroup );
|
||||
if ( feedback )
|
||||
feedback->setProgress( 100 * i / datasetGroups.count() );
|
||||
}
|
||||
|
||||
mExportVectorOption = parameterAsInt( parameters, QStringLiteral( "VECTOR_OPTION" ), context );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariantMap QgsExportMeshVerticesAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
if ( feedback )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
return QVariantMap();
|
||||
feedback->setProgress( 0 );
|
||||
feedback->setProgressText( QObject::tr( "Creating output vector layer" ) );
|
||||
}
|
||||
|
||||
QgsFields fields;
|
||||
for ( int i = 0; i < mDataPerGroup.count(); ++i )
|
||||
{
|
||||
const DataGroup &dataGroup = mDataPerGroup.at( i );
|
||||
if ( dataGroup.metadata.isVector() )
|
||||
{
|
||||
if ( mExportVectorOption == 0 or mExportVectorOption == 2 )
|
||||
{
|
||||
fields.append( QStringLiteral( "%1_x" ).arg( dataGroup.metadata.name() ) );
|
||||
fields.append( QStringLiteral( "%1_y" ).arg( dataGroup.metadata.name() ) );
|
||||
}
|
||||
|
||||
if ( mExportVectorOption == 1 or mExportVectorOption == 2 )
|
||||
{
|
||||
fields.append( QStringLiteral( "%1_mag" ).arg( dataGroup.metadata.name() ) );
|
||||
fields.append( QStringLiteral( "%1_dir" ).arg( dataGroup.metadata.name() ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
fields.append( dataGroup.metadata.name() );
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem outputCrs = parameterAsCrs( parameters, QStringLiteral( "CRS_OUTPUT" ), context );
|
||||
QString identifier;
|
||||
QgsFeatureSink *sink = parameterAsSink( parameters,
|
||||
QStringLiteral( "OUTPUT" ),
|
||||
context,
|
||||
identifier,
|
||||
fields,
|
||||
QgsWkbTypes::PointZ,
|
||||
outputCrs );
|
||||
if ( !sink )
|
||||
return QVariantMap();
|
||||
|
||||
if ( feedback )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
return QVariantMap();
|
||||
feedback->setProgress( 0 );
|
||||
feedback->setProgressText( QObject::tr( "Creating points for each vertices" ) );
|
||||
}
|
||||
|
||||
int verticesCount = mNativeMesh.vertexCount();
|
||||
for ( int i = 0; i < verticesCount; ++i )
|
||||
{
|
||||
QgsAttributes attributes;
|
||||
for ( const DataGroup &dataGroup : mDataPerGroup )
|
||||
{
|
||||
const QgsMeshDatasetGroupMetadata &meta = dataGroup.metadata;
|
||||
const QgsMeshDatasetValue &value = dataGroup.datasetValues.value( i );
|
||||
if ( meta.isVector() )
|
||||
{
|
||||
QVector<double> vector = vectorValue( dataGroup.datasetValues.value( i ), mExportVectorOption );
|
||||
for ( double value : vector )
|
||||
{
|
||||
attributes.append( value );
|
||||
}
|
||||
}
|
||||
else
|
||||
attributes.append( value.scalar() );
|
||||
}
|
||||
|
||||
QgsFeature feat;
|
||||
QgsGeometry geom( new QgsPoint( mNativeMesh.vertex( i ) ) );
|
||||
try
|
||||
{
|
||||
geom.transform( mTransform );
|
||||
}
|
||||
catch ( QgsCsException &e )
|
||||
{
|
||||
geom = QgsGeometry( new QgsPoint( mNativeMesh.vertex( i ) ) );
|
||||
feedback->reportError( QObject::tr( "Could not transform point to destination CRS" ) );
|
||||
}
|
||||
feat.setGeometry( geom );
|
||||
feat.setAttributes( attributes );
|
||||
|
||||
sink->addFeature( feat );
|
||||
|
||||
if ( feedback )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
return QVariantMap();
|
||||
feedback->setProgress( 100 * i / verticesCount );
|
||||
}
|
||||
}
|
||||
|
||||
const QString fileName = parameterAsFile( parameters, QStringLiteral( "OUTPUT" ), context );
|
||||
|
||||
QVariantMap ret;
|
||||
ret[QStringLiteral( "OUTPUT" )] = identifier;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///@endcond PRIVATE
|
62
src/analysis/processing/qgsalgorithmexportmeshvertices.h
Normal file
62
src/analysis/processing/qgsalgorithmexportmeshvertices.h
Normal file
@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmtinmeshcreation.h
|
||||
---------------------------
|
||||
begin : October 2020
|
||||
copyright : (C) 2020 by Vincent Cloarec
|
||||
email : vcloarec at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSALGORITHMEXPORTMESHVERTICES_H
|
||||
#define QGSALGORITHMEXPORTMESHVERTICES_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
#include "qgsmeshdataset.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
class QgsExportMeshVerticesAlgorithm : public QgsProcessingAlgorithm
|
||||
{
|
||||
public:
|
||||
QString group() const override;
|
||||
QString groupId() const override;
|
||||
QString shortHelpString() const override;
|
||||
QString name() const override;
|
||||
QString displayName() const override;
|
||||
|
||||
protected:
|
||||
QgsProcessingAlgorithm *createInstance() const override;
|
||||
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
QVariantMap processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
private:
|
||||
QgsMesh mNativeMesh;
|
||||
|
||||
struct DataGroup
|
||||
{
|
||||
QgsMeshDatasetGroupMetadata metadata;
|
||||
QgsMeshDataBlock datasetValues;
|
||||
QgsMeshDataBlock activeFaceFlagValues;
|
||||
};
|
||||
|
||||
QList<DataGroup> mDataPerGroup;
|
||||
QgsCoordinateTransform mTransform;
|
||||
int mExportVectorOption = 2;
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMEXPORTMESHVERTICES_H
|
@ -55,6 +55,7 @@
|
||||
#include "qgsalgorithmexecutepostgisquery.h"
|
||||
#include "qgsalgorithmexecutespatialitequery.h"
|
||||
#include "qgsalgorithmexecutespatialitequeryregistered.h"
|
||||
#include "qgsalgorithmexportmeshvertices.h"
|
||||
#include "qgsalgorithmexplode.h"
|
||||
#include "qgsalgorithmexplodehstore.h"
|
||||
#include "qgsalgorithmextendlines.h"
|
||||
@ -283,6 +284,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
|
||||
addAlgorithm( new QgsExecuteSpatialiteQueryAlgorithm() );
|
||||
addAlgorithm( new QgsExplodeAlgorithm() );
|
||||
addAlgorithm( new QgsExplodeHstoreAlgorithm() );
|
||||
addAlgorithm( new QgsExportMeshVerticesAlgorithm );
|
||||
addAlgorithm( new QgsExtendLinesAlgorithm() );
|
||||
addAlgorithm( new QgsExtentFromLayerAlgorithm() );
|
||||
addAlgorithm( new QgsExtentToLayerAlgorithm() );
|
||||
|
@ -164,6 +164,7 @@ SET(QGIS_CORE_SRCS
|
||||
processing/qgsprocessingparameteraggregate.cpp
|
||||
processing/qgsprocessingparameterdxflayers.cpp
|
||||
processing/qgsprocessingparameterfieldmap.cpp
|
||||
processing/qgsprocessingparametermeshdataset.cpp
|
||||
processing/qgsprocessingparameters.cpp
|
||||
processing/qgsprocessingparametertininputlayers.cpp
|
||||
processing/qgsprocessingparametertype.cpp
|
||||
@ -1358,6 +1359,7 @@ SET(QGIS_CORE_HDRS
|
||||
processing/qgsprocessingparameteraggregate.h
|
||||
processing/qgsprocessingparameterdxflayers.h
|
||||
processing/qgsprocessingparameterfieldmap.h
|
||||
processing/qgsprocessingparametermeshdataset.h
|
||||
processing/qgsprocessingparameters.h
|
||||
processing/qgsprocessingparametertininputlayers.h
|
||||
processing/qgsprocessingparametertype.h
|
||||
|
@ -123,7 +123,6 @@ QgsDateTimeRange QgsMeshDataProviderTemporalCapabilities::timeExtent( const QDat
|
||||
if ( !groupReference.isValid() ) //the dataset group has not a valid reference time -->take global reference
|
||||
groupReference = mGlobalReferenceDateTime;
|
||||
|
||||
|
||||
if ( !groupReference.isValid() )
|
||||
groupReference = reference;
|
||||
|
||||
|
@ -327,7 +327,7 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
|
||||
int extraDatasetGroupCount() const;
|
||||
|
||||
/**
|
||||
* Returns the list of indexes of dataset groups count handled by the layer
|
||||
* Returns the list of indexes of dataset groups handled by the layer
|
||||
*
|
||||
* \note indexes are used to distinguish all the dataset groups handled by the layer (from dataprovider, extra dataset group,...)
|
||||
* In the layer scope, those indexes can be different from the data provider indexes.
|
||||
|
@ -345,17 +345,27 @@ QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
|
||||
{
|
||||
assert( nativeMesh );
|
||||
Q_UNUSED( method );
|
||||
assert( method == QgsMeshRendererScalarSettings::NeighbourAverage );
|
||||
|
||||
|
||||
// assuming that native vertex count = triangular vertex count
|
||||
assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
|
||||
int vertexCount = triangularMesh->vertices().size();
|
||||
|
||||
return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
|
||||
}
|
||||
|
||||
QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces,
|
||||
const QgsMesh &nativeMesh,
|
||||
QgsMeshDataBlock *active,
|
||||
QgsMeshRendererScalarSettings::DataResamplingMethod method )
|
||||
{
|
||||
int vertexCount = nativeMesh.vertexCount();
|
||||
assert( method == QgsMeshRendererScalarSettings::NeighbourAverage );
|
||||
|
||||
QVector<double> res( vertexCount, 0.0 );
|
||||
// for face datasets do simple average of the valid values of all faces that contains this vertex
|
||||
QVector<int> count( vertexCount, 0 );
|
||||
|
||||
for ( int i = 0; i < nativeMesh->faces.size(); ++i )
|
||||
for ( int i = 0; i < nativeMesh.faceCount(); ++i )
|
||||
{
|
||||
if ( !active || active->active( i ) )
|
||||
{
|
||||
@ -363,7 +373,7 @@ QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
|
||||
if ( !std::isnan( val ) )
|
||||
{
|
||||
// assign for all vertices
|
||||
const QgsMeshFace &face = nativeMesh->faces.at( i );
|
||||
const QgsMeshFace &face = nativeMesh.faces.at( i );
|
||||
for ( int j = 0; j < face.size(); ++j )
|
||||
{
|
||||
int vertexIndex = face[j];
|
||||
@ -449,9 +459,21 @@ QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMeshLa
|
||||
0,
|
||||
datacount );
|
||||
|
||||
if ( vals.isValid() )
|
||||
return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, *activeFaceFlagValues, method );
|
||||
}
|
||||
|
||||
QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMesh &nativeMesh,
|
||||
const QgsMeshDatasetGroupMetadata &groupMetadata,
|
||||
const QgsMeshDataBlock &datasetValues,
|
||||
QgsMeshDataBlock &activeFaceFlagValues,
|
||||
const QgsMeshRendererScalarSettings::DataResamplingMethod method )
|
||||
{
|
||||
QVector<double> ret;
|
||||
bool scalarDataOnVertices = groupMetadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
|
||||
|
||||
if ( datasetValues.isValid() )
|
||||
{
|
||||
ret = QgsMeshLayerUtils::calculateMagnitudes( vals );
|
||||
ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
|
||||
|
||||
if ( !scalarDataOnVertices )
|
||||
{
|
||||
@ -459,8 +481,7 @@ QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMeshLa
|
||||
ret = QgsMeshLayerUtils::interpolateFromFacesData(
|
||||
ret,
|
||||
nativeMesh,
|
||||
triangularMesh,
|
||||
activeFaceFlagValues,
|
||||
&activeFaceFlagValues,
|
||||
method );
|
||||
}
|
||||
}
|
||||
|
@ -235,6 +235,18 @@ class CORE_EXPORT QgsMeshLayerUtils
|
||||
QgsMeshRendererScalarSettings::DataResamplingMethod method
|
||||
);
|
||||
|
||||
/**
|
||||
* Interpolate values on vertices from values on faces
|
||||
*
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
static QVector<double> interpolateFromFacesData(
|
||||
const QVector<double> &valuesOnFaces,
|
||||
const QgsMesh &nativeMesh,
|
||||
QgsMeshDataBlock *active,
|
||||
QgsMeshRendererScalarSettings::DataResamplingMethod method
|
||||
);
|
||||
|
||||
/**
|
||||
* Resamples values on vertices to values on faces
|
||||
*
|
||||
@ -250,11 +262,11 @@ class CORE_EXPORT QgsMeshLayerUtils
|
||||
|
||||
/**
|
||||
* Calculates magnitude values ont vertices from the given QgsMeshDataBlock.
|
||||
* If the values are defined on faces,
|
||||
* If the values are defined on faces, the values are interpolated with the given method
|
||||
* \param meshLayer the mesh layer
|
||||
* \param index the dataset index that contains the data
|
||||
* \param activeFaceFlagValues pointer to the QVector containing active face flag values
|
||||
* \param method used to inteprolate the values on vertices if needed
|
||||
* \param method used to interpolate the values on vertices if needed
|
||||
* \returns magnitude values of the dataset on all the vertices
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
@ -264,6 +276,25 @@ class CORE_EXPORT QgsMeshLayerUtils
|
||||
QgsMeshDataBlock *activeFaceFlagValues,
|
||||
const QgsMeshRendererScalarSettings::DataResamplingMethod method = QgsMeshRendererScalarSettings::NeighbourAverage );
|
||||
|
||||
/**
|
||||
* Calculates magnitude values on vertices from the given QgsMeshDataBlock.
|
||||
* If the values are defined on faces, the values are interpolated with the given method
|
||||
* This method is thread safe.
|
||||
* \param nativeMesh the native mesh
|
||||
* \param groupMetadata the metadata of the group where come from the dataset values
|
||||
* \param datasetValues block containing the dataset values
|
||||
* \param activeFaceFlagValues block containing active face flag values
|
||||
* \param method used to interpolate the values on vertices if needed
|
||||
* \returns magnitude values of the dataset on all the vertices
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
static QVector<double> calculateMagnitudeOnVertices(
|
||||
const QgsMesh &nativeMesh,
|
||||
const QgsMeshDatasetGroupMetadata &groupMetadata,
|
||||
const QgsMeshDataBlock &datasetValues,
|
||||
QgsMeshDataBlock &activeFaceFlagValues,
|
||||
const QgsMeshRendererScalarSettings::DataResamplingMethod method = QgsMeshRendererScalarSettings::NeighbourAverage );
|
||||
|
||||
/**
|
||||
* Calculates the bounding box of the triangle
|
||||
* \param p1 first vertex of the triangle
|
||||
|
@ -72,7 +72,7 @@ class CORE_EXPORT QgsMeshTimeSettings
|
||||
private:
|
||||
|
||||
QString mRelativeTimeFormat = QStringLiteral( "d hh:mm:ss" );
|
||||
QString mAbsoluteTimeFormat = QStringLiteral( "dd.MM.yyyy hh:mm:ss" );
|
||||
QString mAbsoluteTimeFormat = QStringLiteral( "yyyy-MM-dd HH:mm:ss" );
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE( QgsMeshTimeSettings );
|
||||
|
@ -128,6 +128,16 @@ QgsMapLayer *QgsProcessingContext::takeResultLayer( const QString &id )
|
||||
return tempLayerStore.takeMapLayer( tempLayerStore.mapLayer( id ) );
|
||||
}
|
||||
|
||||
QgsDateTimeRange QgsProcessingContext::currentTimeRange() const
|
||||
{
|
||||
return mCurrentTimeRange;
|
||||
}
|
||||
|
||||
void QgsProcessingContext::setCurrentTimeRange( const QgsDateTimeRange ¤tTimeRange )
|
||||
{
|
||||
mCurrentTimeRange = currentTimeRange;
|
||||
}
|
||||
|
||||
QString QgsProcessingContext::ellipsoid() const
|
||||
{
|
||||
return mEllipsoid;
|
||||
|
@ -216,6 +216,22 @@ class CORE_EXPORT QgsProcessingContext
|
||||
*/
|
||||
void setAreaUnit( QgsUnitTypes::AreaUnit areaUnit );
|
||||
|
||||
/**
|
||||
* Returns the current time range to use for temporal operations.
|
||||
*
|
||||
* \see setCurrentTimeRange()
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
QgsDateTimeRange currentTimeRange() const;
|
||||
|
||||
/**
|
||||
* Sets the \a current time range to use for temporal operations.
|
||||
*
|
||||
* \see currentTimeRange()
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
void setCurrentTimeRange( const QgsDateTimeRange ¤tTimeRange );
|
||||
|
||||
/**
|
||||
* Returns a reference to the layer store used for storing temporary layers during
|
||||
* algorithm execution.
|
||||
@ -619,6 +635,8 @@ class CORE_EXPORT QgsProcessingContext
|
||||
QgsUnitTypes::DistanceUnit mDistanceUnit = QgsUnitTypes::DistanceUnknownUnit;
|
||||
QgsUnitTypes::AreaUnit mAreaUnit = QgsUnitTypes::AreaUnknownUnit;
|
||||
|
||||
QgsDateTimeRange mCurrentTimeRange;
|
||||
|
||||
//! Temporary project owned by the context, used for storing temporarily loaded map layers
|
||||
QgsMapLayerStore tempLayerStore;
|
||||
QgsExpressionContext mExpressionContext;
|
||||
|
293
src/core/processing/qgsprocessingparametermeshdataset.cpp
Normal file
293
src/core/processing/qgsprocessingparametermeshdataset.cpp
Normal file
@ -0,0 +1,293 @@
|
||||
/***************************************************************************
|
||||
qgsprocessingparametermeshdataset.cpp
|
||||
---------------------
|
||||
Date : October 2020
|
||||
Copyright : (C) 2020 by Vincent Cloarec
|
||||
Email : vcloarec at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsprocessingparametermeshdataset.h"
|
||||
|
||||
/// @cond PRIVATE
|
||||
///
|
||||
QgsProcessingParameterMeshDatasetGroups::QgsProcessingParameterMeshDatasetGroups( const QString &name,
|
||||
const QString &description,
|
||||
const QString &meshLayerParameterName,
|
||||
const QgsMeshDatasetGroupMetadata::DataType dataType,
|
||||
bool optional ):
|
||||
QgsProcessingParameterDefinition( name, description, QVariant(), optional, QString() ),
|
||||
mMeshLayerParameterName( meshLayerParameterName ),
|
||||
mDataType( dataType )
|
||||
{
|
||||
}
|
||||
|
||||
QgsProcessingParameterDefinition *QgsProcessingParameterMeshDatasetGroups::clone() const
|
||||
{
|
||||
return new QgsProcessingParameterMeshDatasetGroups( name(), description(), mMeshLayerParameterName, mDataType );
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetGroups::type() const
|
||||
{
|
||||
return typeName();
|
||||
}
|
||||
|
||||
bool QgsProcessingParameterMeshDatasetGroups::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context ) const
|
||||
{
|
||||
Q_UNUSED( context );
|
||||
return valueIsAcceptable( input, mFlags & FlagOptional );
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetGroups::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
|
||||
{
|
||||
Q_UNUSED( context );
|
||||
QStringList parts;
|
||||
const QVariantList variantDatasetGroupIndexes = value.toList();
|
||||
for ( const QVariant &variantIndex : variantDatasetGroupIndexes )
|
||||
parts.append( QString::number( variantIndex.toInt() ) );
|
||||
|
||||
return parts.join( ',' ).prepend( '[' ).append( ']' );
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetGroups::asPythonString( QgsProcessing::PythonOutputType outputType ) const
|
||||
{
|
||||
switch ( outputType )
|
||||
{
|
||||
case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
|
||||
{
|
||||
QString code = QStringLiteral( "QgsProcessingParameterMeshDatasetGroups('%1', '%2'" )
|
||||
.arg( name(), description() );
|
||||
if ( !mMeshLayerParameterName.isEmpty() )
|
||||
code += QStringLiteral( ", meshLayerParameterName=%1" ).arg( QgsProcessingUtils::stringToPythonLiteral( mMeshLayerParameterName ) );
|
||||
|
||||
switch ( mDataType )
|
||||
{
|
||||
case QgsMeshDatasetGroupMetadata::DataOnFaces:
|
||||
code += QStringLiteral( ", dataType=QgsMeshDatasetGroupMetadata.DataOnFaces" );
|
||||
break;
|
||||
case QgsMeshDatasetGroupMetadata::DataOnVertices:
|
||||
code += QStringLiteral( ", dataType=QgsMeshDatasetGroupMetadata.DataOnVertices" );
|
||||
break;
|
||||
case QgsMeshDatasetGroupMetadata::DataOnVolumes:
|
||||
code += QStringLiteral( ", dataType=QgsMeshDatasetGroupMetadata.DataOnVolumes" );
|
||||
break;
|
||||
case QgsMeshDatasetGroupMetadata::DataOnEdges:
|
||||
code += QStringLiteral( ", dataType=QgsMeshDatasetGroupMetadata.DataOnEdges" );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( mFlags & FlagOptional )
|
||||
code += QStringLiteral( ", optional=True" );
|
||||
code += ')';
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QStringList QgsProcessingParameterMeshDatasetGroups::dependsOnOtherParameters() const
|
||||
{
|
||||
if ( mMeshLayerParameterName.isEmpty() )
|
||||
return QStringList();
|
||||
else
|
||||
return QStringList() << mMeshLayerParameterName;
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetGroups::meshLayerParameterName() const
|
||||
{
|
||||
return mMeshLayerParameterName;
|
||||
}
|
||||
|
||||
QList<int> QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( const QVariant &value )
|
||||
{
|
||||
if ( !valueIsAcceptable( value, true ) )
|
||||
return QList<int>();
|
||||
QVariantList list = value.toList();
|
||||
QList<int> ret;
|
||||
for ( const QVariant &v : list )
|
||||
ret.append( v.toInt() );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool QgsProcessingParameterMeshDatasetGroups::valueIsAcceptable( const QVariant &input, bool allowEmpty )
|
||||
{
|
||||
if ( !input.isValid() )
|
||||
return allowEmpty;
|
||||
|
||||
if ( input.type() != QVariant::List )
|
||||
return false;
|
||||
const QVariantList list = input.toList();
|
||||
|
||||
if ( !allowEmpty && list.isEmpty() )
|
||||
return false;
|
||||
|
||||
for ( const QVariant &var : list )
|
||||
if ( var.type() != QVariant::Int )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsProcessingParameterMeshDatasetTime::QgsProcessingParameterMeshDatasetTime( const QString &name,
|
||||
const QString &description,
|
||||
const QString &meshLayerParameterName,
|
||||
const QString &datasetGroupParameterName )
|
||||
: QgsProcessingParameterDefinition( name, description, QVariant() )
|
||||
, mMeshLayerParameterName( meshLayerParameterName )
|
||||
, mDatasetGroupParameterName( datasetGroupParameterName )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QgsProcessingParameterDefinition *QgsProcessingParameterMeshDatasetTime::clone() const
|
||||
{
|
||||
return new QgsProcessingParameterMeshDatasetTime( name(), description(), mMeshLayerParameterName, mDatasetGroupParameterName );
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetTime::type() const
|
||||
{
|
||||
return typeName();
|
||||
}
|
||||
|
||||
bool QgsProcessingParameterMeshDatasetTime::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context ) const
|
||||
{
|
||||
Q_UNUSED( context );
|
||||
return valueIsAcceptable( input, mFlags & FlagOptional );
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetTime::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
|
||||
{
|
||||
Q_UNUSED( context );
|
||||
QStringList parts;
|
||||
const QVariantMap variantTimeDataset = value.toMap();
|
||||
parts << QStringLiteral( "'type': " ) + QgsProcessingUtils::variantToPythonLiteral( variantTimeDataset.value( QStringLiteral( "type" ) ).toString() );
|
||||
|
||||
if ( variantTimeDataset.value( QStringLiteral( "type" ) ) == QStringLiteral( "dataset-time-step" ) )
|
||||
{
|
||||
QVariantList datasetIndex = variantTimeDataset.value( QStringLiteral( "value" ) ).toList();
|
||||
parts << QStringLiteral( "'value': " ) + QString( "QgsMeshDatasetIndex(%1,%2)" ).arg( datasetIndex.at( 0 ).toString() ).arg( datasetIndex.at( 1 ).toString() );
|
||||
}
|
||||
else if ( variantTimeDataset.value( QStringLiteral( "type" ) ) == QStringLiteral( "defined-date-time" ) )
|
||||
{
|
||||
parts << QStringLiteral( "'value': " ) + QgsProcessingUtils::variantToPythonLiteral( variantTimeDataset.value( QStringLiteral( "value" ) ) );
|
||||
}
|
||||
|
||||
return parts.join( ',' ).prepend( '{' ).append( '}' );
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetTime::asPythonString( QgsProcessing::PythonOutputType outputType ) const
|
||||
{
|
||||
switch ( outputType )
|
||||
{
|
||||
case QgsProcessing::PythonQgsProcessingAlgorithmSubclass:
|
||||
{
|
||||
QString code = QStringLiteral( "QgsProcessingParameterMeshDatasetTime('%1', '%2'" )
|
||||
.arg( name(), description() );
|
||||
if ( !mMeshLayerParameterName.isEmpty() )
|
||||
code += QStringLiteral( ", meshLayerParameterName=%1" ).arg( QgsProcessingUtils::stringToPythonLiteral( mMeshLayerParameterName ) );
|
||||
|
||||
if ( !mDatasetGroupParameterName.isEmpty() )
|
||||
code += QStringLiteral( ", datasetGroupParameterName=%1" ).arg( QgsProcessingUtils::stringToPythonLiteral( mDatasetGroupParameterName ) );
|
||||
|
||||
if ( mFlags & FlagOptional )
|
||||
code += QStringLiteral( ", optional=True" );
|
||||
code += ')';
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QStringList QgsProcessingParameterMeshDatasetTime::dependsOnOtherParameters() const
|
||||
{
|
||||
QStringList otherParameters;
|
||||
if ( !mMeshLayerParameterName.isEmpty() )
|
||||
otherParameters << mMeshLayerParameterName;
|
||||
|
||||
if ( !mDatasetGroupParameterName.isEmpty() )
|
||||
otherParameters << mMeshLayerParameterName << mDatasetGroupParameterName;
|
||||
|
||||
return otherParameters;
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetTime::meshLayerParameterName() const
|
||||
{
|
||||
return mMeshLayerParameterName;
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetTime::datasetGroupParameterName() const
|
||||
{
|
||||
return mDatasetGroupParameterName;
|
||||
}
|
||||
|
||||
QString QgsProcessingParameterMeshDatasetTime::valueAsTimeType( const QVariant &value )
|
||||
{
|
||||
if ( !valueIsAcceptable( value, false ) )
|
||||
return QString();
|
||||
|
||||
return value.toMap().value( QStringLiteral( "type" ) ).toString();
|
||||
}
|
||||
|
||||
QgsMeshDatasetIndex QgsProcessingParameterMeshDatasetTime::timeValueAsDatasetIndex( const QVariant &value )
|
||||
{
|
||||
if ( !valueIsAcceptable( value, false ) || valueAsTimeType( value ) != QStringLiteral( "dataset-time-step" ) )
|
||||
return QgsMeshDatasetIndex( -1, -1 );
|
||||
|
||||
QVariantList list = value.toMap().value( QStringLiteral( "value" ) ).toList();
|
||||
return QgsMeshDatasetIndex( list.at( 0 ).toInt(), list.at( 1 ).toInt() );
|
||||
}
|
||||
|
||||
QDateTime QgsProcessingParameterMeshDatasetTime::timeValueAsDefinedDateTime( const QVariant &value )
|
||||
{
|
||||
if ( !valueIsAcceptable( value, false ) && valueAsTimeType( value ) != QStringLiteral( "defined-date-time" ) )
|
||||
return QDateTime();
|
||||
|
||||
return value.toMap().value( QStringLiteral( "value" ) ).toDateTime();
|
||||
}
|
||||
|
||||
bool QgsProcessingParameterMeshDatasetTime::valueIsAcceptable( const QVariant &input, bool allowEmpty )
|
||||
{
|
||||
if ( !input.isValid() )
|
||||
return allowEmpty;
|
||||
|
||||
if ( input.type() != QVariant::Map )
|
||||
return false;
|
||||
const QVariantMap map = input.toMap();
|
||||
if ( ! map.contains( QStringLiteral( "type" ) ) )
|
||||
return false;
|
||||
|
||||
QString type = map.value( QStringLiteral( "type" ) ).toString();
|
||||
QVariant value = map.value( QStringLiteral( "value" ) );
|
||||
|
||||
if ( type == QStringLiteral( "static" ) || type == QStringLiteral( "current-context-time" ) )
|
||||
return true;
|
||||
|
||||
if ( type == QStringLiteral( "dataset-time-step" ) )
|
||||
{
|
||||
if ( value.type() != QVariant::List )
|
||||
return false;
|
||||
QVariantList list = value.toList();
|
||||
if ( value.toList().count() != 2 )
|
||||
return false;
|
||||
if ( list.at( 0 ).type() != QVariant::Int || list.at( 1 ).type() != QVariant::Int )
|
||||
return false;
|
||||
}
|
||||
else if ( type == QStringLiteral( "defined-date-time" ) )
|
||||
{
|
||||
if ( value.type() != QVariant::DateTime )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @endcond PRIVATE
|
258
src/core/processing/qgsprocessingparametermeshdataset.h
Normal file
258
src/core/processing/qgsprocessingparametermeshdataset.h
Normal file
@ -0,0 +1,258 @@
|
||||
/***************************************************************************
|
||||
qgsprocessingparametermeshdataset.h
|
||||
---------------------
|
||||
Date : October 2020
|
||||
Copyright : (C) 2020 by Vincent Cloarec
|
||||
Email : vcloarec at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSPROCESSINGPARAMETERMESHDATASET_H
|
||||
#define QGSPROCESSINGPARAMETERMESHDATASET_H
|
||||
|
||||
#include "qgsprocessingparameters.h"
|
||||
#include "qgsprocessingparametertype.h"
|
||||
#include "qgsmeshdataset.h"
|
||||
|
||||
/**
|
||||
* A parameter for processing algorithms that need a list of mesh dataset groups
|
||||
* A valid value for this parameter is a list (QVariantList) of dataset groups index in the mesh layer scope
|
||||
* Dataset group index can be evaluated with the method valueAsDatasetGroup()
|
||||
*
|
||||
* \note This parameter is dependent on a mesh layer parameter (see QgsProcessingParameterMeshLayer)
|
||||
*
|
||||
* \ingroup core
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class CORE_EXPORT QgsProcessingParameterMeshDatasetGroups : public QgsProcessingParameterDefinition
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* \param name name of the parameter
|
||||
* \param description description of the parameter
|
||||
* \param meshLayerParameterName name of the associated mesh layer parameter
|
||||
* \param dataType data type supported by the parameter
|
||||
* \param optional whether the parameter is optional
|
||||
*/
|
||||
QgsProcessingParameterMeshDatasetGroups( const QString &name,
|
||||
const QString &description = QString(),
|
||||
const QString &meshLayerParameterName = QString(),
|
||||
QgsMeshDatasetGroupMetadata::DataType dataType = QgsMeshDatasetGroupMetadata::DataOnVertices,
|
||||
bool optional = false );
|
||||
|
||||
QgsProcessingParameterDefinition *clone() const override SIP_FACTORY;
|
||||
QString type() const override;
|
||||
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
|
||||
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
|
||||
QString asPythonString( QgsProcessing::PythonOutputType outputType = QgsProcessing::PythonQgsProcessingAlgorithmSubclass ) const override;
|
||||
QStringList dependsOnOtherParameters() const override;
|
||||
|
||||
//! Returns the type name for the parameter class.
|
||||
static QString typeName() { return QStringLiteral( "meshdatasetgroups" ); }
|
||||
|
||||
//! Returns the name of the mesh layer parameter
|
||||
QString meshLayerParameterName() const;
|
||||
|
||||
//! Returns the data type supported by the parameter
|
||||
QgsMeshDatasetGroupMetadata::DataType dataType() const {return mDataType;}
|
||||
|
||||
//! Returns the \a value as a list if dataset group indexes
|
||||
static QList<int> valueAsDatasetGroup( const QVariant &value );
|
||||
|
||||
private:
|
||||
QString mMeshLayerParameterName;
|
||||
QgsMeshDatasetGroupMetadata::DataType mDataType = QgsMeshDatasetGroupMetadata::DataOnVertices;
|
||||
|
||||
static bool valueIsAcceptable( const QVariant &input, bool allowEmpty );
|
||||
};
|
||||
|
||||
#ifndef SIP_RUN
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* Parameter type definition for QgsProcessingParameterMeshDatasetGroups.
|
||||
*
|
||||
* \ingroup core
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class CORE_EXPORT QgsProcessingParameterTypeMeshDatasetGroups : public QgsProcessingParameterType
|
||||
{
|
||||
public:
|
||||
QgsProcessingParameterDefinition *create( const QString &name ) const override SIP_FACTORY
|
||||
{
|
||||
return new QgsProcessingParameterMeshDatasetGroups( name );
|
||||
}
|
||||
|
||||
QString description() const override
|
||||
{
|
||||
return QCoreApplication::translate( "Processing", "An input allowing selection dataset groups from a mesh layer" );
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
return QCoreApplication::translate( "Processing", "Mesh dataset groups" );
|
||||
}
|
||||
|
||||
QString id() const override
|
||||
{
|
||||
return QgsProcessingParameterMeshDatasetGroups::typeName();
|
||||
}
|
||||
|
||||
QString pythonImportString() const override
|
||||
{
|
||||
return QStringLiteral( "from qgis.core import QgsProcessingParameterMeshDatasetGroups" );
|
||||
}
|
||||
|
||||
QString className() const override
|
||||
{
|
||||
return QStringLiteral( "QgsProcessingParameterMeshDatasetGroups" );
|
||||
}
|
||||
|
||||
QStringList acceptedPythonTypes() const override
|
||||
{
|
||||
return QStringList() << QObject::tr( "list[int]: list of dataset group indexes, see QgsProcessingParameterMeshDatasetGroups docs" );
|
||||
}
|
||||
};
|
||||
|
||||
///@endcond
|
||||
#endif //SIP_RUN
|
||||
|
||||
/**
|
||||
* A parameter for processing algorithms that need a list of mesh dataset index from time parameter
|
||||
* A valid value for this parameter is a map (QVariantMap) with in this form:
|
||||
*
|
||||
* - "type" : the type of time settings "current-context-time", "defined-date-time", "dataset-time-step" or "none" if all the dataset groups are static
|
||||
* - "value" : nothing if type is "static" or "current-context-time", QDateTime if "defined-date-time" or, for "dataset_time_step", list of two int representing the dataset index that is the reference for the time step
|
||||
*
|
||||
* \note This parameter is dependent on a mesh layer parameter (\see QgsProcessingParameterMeshLayer)
|
||||
* and on mesh datast group parameter (\see QgsProcessingParameterMeshDatasetGroups)
|
||||
*
|
||||
* \ingroup core
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class CORE_EXPORT QgsProcessingParameterMeshDatasetTime : public QgsProcessingParameterDefinition
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* \param name name of the parameter
|
||||
* \param description description of the parameter
|
||||
* \param meshLayerParameterName name of the associated mesh layer parameter (\see QgsProcessingParameterMeshLayer)
|
||||
* \param datasetGroupParameterName name of the associated dataset group parameter (\see QgsProcessingParameterMeshDatasetGroups)
|
||||
*/
|
||||
QgsProcessingParameterMeshDatasetTime(
|
||||
const QString &name,
|
||||
const QString &description = QString(),
|
||||
const QString &meshLayerParameterName = QString(),
|
||||
const QString &datasetGroupParameterName = QString() );
|
||||
|
||||
QgsProcessingParameterDefinition *clone() const override SIP_FACTORY;
|
||||
QString type() const override;
|
||||
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
|
||||
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
|
||||
QString asPythonString( QgsProcessing::PythonOutputType outputType = QgsProcessing::PythonQgsProcessingAlgorithmSubclass ) const override;
|
||||
QStringList dependsOnOtherParameters() const override;
|
||||
|
||||
//! Returns the type name for the parameter class.
|
||||
static QString typeName() { return QStringLiteral( "meshdatasettime" ); }
|
||||
|
||||
//! Returns the name of the mesh layer parameter
|
||||
QString meshLayerParameterName() const;
|
||||
|
||||
//! Returns the name of the dataset groups parameter
|
||||
QString datasetGroupParameterName() const;
|
||||
|
||||
/**
|
||||
* Returns the \a dataset value time type as a string :
|
||||
* current-context-time : the time is store in the processing context (e.g. current canvas time), in this case the value does not contain any time value
|
||||
* defined-date-time : absolute time of type QDateTime
|
||||
* dataset-time-step : a time step of existing dataset, in this case the time takes the form of a QMeshDatasetIndex with value to the corresponding dataset index
|
||||
* static : dataset groups are all static, in this case the value does not contain any time value
|
||||
*/
|
||||
static QString valueAsTimeType( const QVariant &value );
|
||||
|
||||
/**
|
||||
* Returns the \a value as a QgsMeshDatasetIndex if the value has "dataset-time-step" type.
|
||||
* If the value has the wrong type return an invalid dataset index
|
||||
*
|
||||
* \see valueAsTimeType()
|
||||
*/
|
||||
static QgsMeshDatasetIndex timeValueAsDatasetIndex( const QVariant &value );
|
||||
|
||||
/**
|
||||
* Returns the \a value as a QDateTime if the value has "defined-date-time" type.
|
||||
* If the value has the wrong type return an invalid QDatetime
|
||||
*
|
||||
* \see valueAsTimeType()
|
||||
*/
|
||||
static QDateTime timeValueAsDefinedDateTime( const QVariant &value );
|
||||
|
||||
private:
|
||||
QString mMeshLayerParameterName;
|
||||
QString mDatasetGroupParameterName;
|
||||
|
||||
static bool valueIsAcceptable( const QVariant &input, bool allowEmpty );
|
||||
};
|
||||
|
||||
#ifndef SIP_RUN
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* Parameter type definition for QgsProcessingParameterMeshDatasetTime.
|
||||
*
|
||||
* \ingroup core
|
||||
* \since QGIS 3.18
|
||||
*/
|
||||
class CORE_EXPORT QgsProcessingParameterTypeMeshDatasetTime: public QgsProcessingParameterType
|
||||
{
|
||||
public:
|
||||
QgsProcessingParameterDefinition *create( const QString &name ) const override SIP_FACTORY
|
||||
{
|
||||
return new QgsProcessingParameterMeshDatasetTime( name );
|
||||
}
|
||||
|
||||
QString description() const override
|
||||
{
|
||||
return QCoreApplication::translate( "Processing", "An input allowing selection of dataset index from a mesh layer by time setting" );
|
||||
}
|
||||
|
||||
QString name() const override
|
||||
{
|
||||
return QCoreApplication::translate( "Processing", "Mesh dataset time" );
|
||||
}
|
||||
|
||||
QString id() const override
|
||||
{
|
||||
return QgsProcessingParameterMeshDatasetTime::typeName();
|
||||
}
|
||||
|
||||
QString pythonImportString() const override
|
||||
{
|
||||
return QStringLiteral( "from qgis.core import QgsProcessingParameterMeshDatasetTime" );
|
||||
}
|
||||
|
||||
QString className() const override
|
||||
{
|
||||
return QStringLiteral( "QgsProcessingParameterMeshDatasetTime" );
|
||||
}
|
||||
|
||||
QStringList acceptedPythonTypes() const override
|
||||
{
|
||||
return QStringList() << QObject::tr( "dict{}: dictionary, see QgsProcessingParameterMeshDatasetTime docs" );
|
||||
}
|
||||
};
|
||||
|
||||
///@endcond
|
||||
#endif //SIP_RUN
|
||||
|
||||
|
||||
#endif // QGSPROCESSINGPARAMETERMESHDATASET_H
|
@ -337,6 +337,7 @@ class CORE_EXPORT QgsProcessingParameterDefinition
|
||||
#include "qgsprocessingparameterfieldmap.h"
|
||||
#include "qgsprocessingparametertininputlayers.h"
|
||||
#include "qgsprocessingparametervectortilewriterlayers.h"
|
||||
#include "qgsprocessingparametermeshdataset.h"
|
||||
% End
|
||||
SIP_CONVERT_TO_SUBCLASS_CODE
|
||||
if ( sipCpp->type() == QgsProcessingParameterBoolean::typeName() )
|
||||
@ -421,6 +422,10 @@ class CORE_EXPORT QgsProcessingParameterDefinition
|
||||
sipType = sipType_QgsProcessingParameterVectorTileWriterLayers;
|
||||
else if ( sipCpp->type() == QgsProcessingParameterDxfLayers::typeName() )
|
||||
sipType = sipType_QgsProcessingParameterDxfLayers;
|
||||
else if ( sipCpp->type() == QgsProcessingParameterMeshDatasetGroups::typeName() )
|
||||
sipType = sipType_QgsProcessingParameterMeshDatasetGroups;
|
||||
else if ( sipCpp->type() == QgsProcessingParameterMeshDatasetTime::typeName() )
|
||||
sipType = sipType_QgsProcessingParameterMeshDatasetTime;
|
||||
else
|
||||
sipType = nullptr;
|
||||
SIP_END
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "qgsprocessingregistry.h"
|
||||
#include "qgsvectorfilewriter.h"
|
||||
#include "qgsprocessingparametertypeimpl.h"
|
||||
#include "qgsprocessingparametermeshdataset.h"
|
||||
#include "qgsprocessingparametervectortilewriterlayers.h"
|
||||
#include "qgsprocessingparametertininputlayers.h"
|
||||
#include "qgsprocessingparameterfieldmap.h"
|
||||
@ -71,6 +72,8 @@ QgsProcessingRegistry::QgsProcessingRegistry( QObject *parent SIP_TRANSFERTHIS )
|
||||
addParameterType( new QgsProcessingParameterTypeAggregate() );
|
||||
addParameterType( new QgsProcessingParameterTypeTinInputLayers() );
|
||||
addParameterType( new QgsProcessingParameterTypeDxfLayers() );
|
||||
addParameterType( new QgsProcessingParameterTypeMeshDatasetGroups() );
|
||||
addParameterType( new QgsProcessingParameterTypeMeshDatasetTime() );
|
||||
}
|
||||
|
||||
QgsProcessingRegistry::~QgsProcessingRegistry()
|
||||
|
@ -603,6 +603,18 @@ QString QgsProcessingUtils::variantToPythonLiteral( const QVariant &value )
|
||||
return parts.join( ',' ).prepend( '{' ).append( '}' );
|
||||
}
|
||||
|
||||
case QVariant::DateTime:
|
||||
{
|
||||
const QDateTime dateTime = value.toDateTime();
|
||||
return QStringLiteral( "QDateTime(QDate(%1, %2, %3), QTime(%4, %5, %6))" )
|
||||
.arg( dateTime.date().year() )
|
||||
.arg( dateTime.date().month() )
|
||||
.arg( dateTime.date().day() )
|
||||
.arg( dateTime.time().hour() )
|
||||
.arg( dateTime.time().minute() )
|
||||
.arg( dateTime.time().second() );
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -300,6 +300,7 @@ SET(QGIS_GUI_SRCS
|
||||
processing/qgsprocessingmaplayercombobox.cpp
|
||||
processing/qgsprocessingmatrixmodelerwidget.cpp
|
||||
processing/qgsprocessingmatrixparameterdialog.cpp
|
||||
processing/qgsprocessingmeshdatasetwidget.cpp
|
||||
processing/qgsprocessingmodelerparameterwidget.cpp
|
||||
processing/qgsprocessingmultipleselectiondialog.cpp
|
||||
processing/qgsprocessingoutputdestinationwidget.cpp
|
||||
@ -1061,6 +1062,7 @@ SET(QGIS_GUI_HDRS
|
||||
processing/qgsprocessingmaplayercombobox.h
|
||||
processing/qgsprocessingmatrixmodelerwidget.h
|
||||
processing/qgsprocessingmatrixparameterdialog.h
|
||||
processing/qgsprocessingmeshdatasetwidget.h
|
||||
processing/qgsprocessingmodelerparameterwidget.h
|
||||
processing/qgsprocessingmultipleselectiondialog.h
|
||||
processing/qgsprocessingoutputdestinationwidget.h
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "qgsprocessingdxflayerswidgetwrapper.h"
|
||||
#include "qgsprocessingwidgetwrapperimpl.h"
|
||||
#include "qgsprocessingtininputlayerswidget.h"
|
||||
#include "qgsprocessingmeshdatasetwidget.h"
|
||||
#include "qgsprocessingparameters.h"
|
||||
#include "qgis.h"
|
||||
#include "qgslogger.h"
|
||||
@ -75,6 +76,8 @@ QgsProcessingGuiRegistry::QgsProcessingGuiRegistry()
|
||||
addParameterWidgetFactory( new QgsProcessingAggregateWidgetWrapper() );
|
||||
addParameterWidgetFactory( new QgsProcessingTinInputLayersWidgetWrapper() );
|
||||
addParameterWidgetFactory( new QgsProcessingDxfLayersWidgetWrapper() );
|
||||
addParameterWidgetFactory( new QgsProcessingMeshDatasetGroupsWidgetWrapper() );
|
||||
addParameterWidgetFactory( new QgsProcessingMeshDatasetTimeWidgetWrapper() );
|
||||
}
|
||||
|
||||
QgsProcessingGuiRegistry::~QgsProcessingGuiRegistry()
|
||||
|
686
src/gui/processing/qgsprocessingmeshdatasetwidget.cpp
Normal file
686
src/gui/processing/qgsprocessingmeshdatasetwidget.cpp
Normal file
@ -0,0 +1,686 @@
|
||||
/***************************************************************************
|
||||
qgsprocessingmeshdatasetgroupswidget.h
|
||||
---------------------
|
||||
Date : October 2020
|
||||
Copyright : (C) 2020 by Vincent Cloarec
|
||||
Email : vcloarec at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsprocessingmeshdatasetwidget.h"
|
||||
#include "qgsdatetimeedit.h"
|
||||
#include "qgsprocessingmultipleselectiondialog.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgsmeshlayerutils.h"
|
||||
#include "qgsmeshlayertemporalproperties.h"
|
||||
#include "qgspanelwidget.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
/// @cond PRIVATE
|
||||
|
||||
QgsProcessingMeshDatasetGroupsWidget::QgsProcessingMeshDatasetGroupsWidget( QWidget *parent, const QgsProcessingParameterMeshDatasetGroups *param )
|
||||
: QWidget( parent ),
|
||||
mParam( param )
|
||||
{
|
||||
QHBoxLayout *hl = new QHBoxLayout();
|
||||
hl->setContentsMargins( 0, 0, 0, 0 );
|
||||
|
||||
mLineEdit = new QLineEdit();
|
||||
mLineEdit->setEnabled( false );
|
||||
hl->addWidget( mLineEdit, 1 );
|
||||
|
||||
mToolButton = new QToolButton();
|
||||
mToolButton->setText( QString( QChar( 0x2026 ) ) );
|
||||
hl->addWidget( mToolButton );
|
||||
|
||||
setLayout( hl );
|
||||
|
||||
mLineEdit->setText( tr( "%1 dataset groups selected" ).arg( 0 ) );
|
||||
|
||||
mToolButton->setPopupMode( QToolButton::InstantPopup );
|
||||
QMenu *toolButtonMenu = new QMenu( this );
|
||||
mActionCurrentActiveDatasetGroups = toolButtonMenu->addAction( tr( "Current Active Dataset Group" ) );
|
||||
connect( mActionCurrentActiveDatasetGroups,
|
||||
&QAction::triggered, this, &QgsProcessingMeshDatasetGroupsWidget::selectCurrentActiveDatasetGroup );
|
||||
|
||||
mActionAvailableDatasetGroups = toolButtonMenu->addAction( tr( "Select in Available Dataset Groups" ) );
|
||||
connect( mActionAvailableDatasetGroups, &QAction::triggered, this, &QgsProcessingMeshDatasetGroupsWidget::showDialog );
|
||||
|
||||
mToolButton->setMenu( toolButtonMenu );
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetGroupsWidget::setMeshLayer( QgsMeshLayer *layer, bool layerFromProject )
|
||||
{
|
||||
mActionCurrentActiveDatasetGroups->setEnabled( layer && layerFromProject );
|
||||
mActionAvailableDatasetGroups->setEnabled( layer );
|
||||
|
||||
if ( mMeshLayer == layer )
|
||||
return;
|
||||
|
||||
mDatasetGroupsNames.clear();
|
||||
|
||||
if ( layerFromProject )
|
||||
mMeshLayer = layer;
|
||||
else
|
||||
{
|
||||
mMeshLayer = nullptr;
|
||||
if ( layer )
|
||||
{
|
||||
QList<int> datasetGroupsIndexes = layer->datasetGroupsIndexes();
|
||||
for ( int i : datasetGroupsIndexes )
|
||||
{
|
||||
QgsMeshDatasetGroupMetadata meta = layer->datasetGroupMetadata( i );
|
||||
if ( meta.dataType() == mParam->dataType() )
|
||||
{
|
||||
mDatasetGroupsNames[i] = meta.name();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mValue.clear();
|
||||
updateSummaryText();
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetGroupsWidget::setValue( const QVariant &value )
|
||||
{
|
||||
if ( value.isValid() )
|
||||
mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
|
||||
else
|
||||
mValue.clear();
|
||||
|
||||
updateSummaryText();
|
||||
emit changed();
|
||||
}
|
||||
|
||||
QVariant QgsProcessingMeshDatasetGroupsWidget::value() const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetGroupsWidget::showDialog()
|
||||
{
|
||||
QList<int> datasetGroupsIndexes;
|
||||
QStringList options;
|
||||
QVariantList availableOptions;
|
||||
if ( mMeshLayer )
|
||||
{
|
||||
datasetGroupsIndexes = mMeshLayer->datasetGroupsIndexes();
|
||||
for ( int i : datasetGroupsIndexes )
|
||||
{
|
||||
QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( i );
|
||||
if ( meta.dataType() == mParam->dataType() )
|
||||
{
|
||||
availableOptions.append( i );
|
||||
options.append( meta.name() );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i : mDatasetGroupsNames.keys() )
|
||||
{
|
||||
availableOptions.append( i );
|
||||
options.append( mDatasetGroupsNames.value( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this );
|
||||
if ( panel && panel->dockMode() )
|
||||
{
|
||||
QgsProcessingMultipleSelectionPanelWidget *widget = new QgsProcessingMultipleSelectionPanelWidget( availableOptions, mValue );
|
||||
widget->setPanelTitle( tr( "Dataset Groups Available" ) );
|
||||
|
||||
widget->setValueFormatter( [availableOptions, options]( const QVariant & v ) -> QString
|
||||
{
|
||||
const int index = v.toInt();
|
||||
const int pos = availableOptions.indexOf( index );
|
||||
return ( pos >= 0 && pos < options.size() ) ? options.at( pos ) : QString();
|
||||
} );
|
||||
|
||||
connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
|
||||
{
|
||||
setValue( widget->selectedOptions() );
|
||||
} );
|
||||
connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
|
||||
panel->openPanel( widget );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsProcessingMultipleSelectionDialog dlg( availableOptions, mValue, this, Qt::WindowFlags() );
|
||||
|
||||
dlg.setValueFormatter( [datasetGroupsIndexes, options]( const QVariant & v ) -> QString
|
||||
{
|
||||
const int index = v.toInt();
|
||||
const int pos = datasetGroupsIndexes.indexOf( index );
|
||||
return ( pos >= 0 && pos < options.size() ) ? options.at( pos ) : QString();
|
||||
} );
|
||||
if ( dlg.exec() )
|
||||
{
|
||||
setValue( dlg.selectedOptions() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetGroupsWidget::selectCurrentActiveDatasetGroup()
|
||||
{
|
||||
QVariantList options;
|
||||
if ( mMeshLayer && mParam )
|
||||
{
|
||||
int scalarDatasetGroup = mMeshLayer->rendererSettings().activeScalarDatasetGroup();
|
||||
int vectorDatasetGroup = mMeshLayer->rendererSettings().activeVectorDatasetGroup();
|
||||
|
||||
if ( scalarDatasetGroup >= 0 && mMeshLayer->datasetGroupMetadata( scalarDatasetGroup ).dataType() == mParam->dataType() )
|
||||
options.append( scalarDatasetGroup );
|
||||
|
||||
if ( vectorDatasetGroup >= 0
|
||||
&& mMeshLayer->datasetGroupMetadata( vectorDatasetGroup ).dataType() == mParam->dataType()
|
||||
&& vectorDatasetGroup != scalarDatasetGroup )
|
||||
options.append( vectorDatasetGroup );
|
||||
}
|
||||
|
||||
setValue( options );
|
||||
}
|
||||
|
||||
QgsProcessingMeshDatasetGroupsWidgetWrapper::QgsProcessingMeshDatasetGroupsWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent ):
|
||||
QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
|
||||
{}
|
||||
|
||||
QString QgsProcessingMeshDatasetGroupsWidgetWrapper::parameterType() const
|
||||
{
|
||||
return QgsProcessingParameterMeshDatasetGroups::typeName();
|
||||
}
|
||||
|
||||
QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshDatasetGroupsWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
|
||||
{
|
||||
return new QgsProcessingMeshDatasetGroupsWidgetWrapper( parameter, type );
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetGroupsWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
|
||||
{
|
||||
QgsAbstractProcessingParameterWidgetWrapper::postInitialize( wrappers ); //necessary here?
|
||||
switch ( type() )
|
||||
{
|
||||
case QgsProcessingGui::Standard:
|
||||
case QgsProcessingGui::Batch:
|
||||
{
|
||||
for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
|
||||
{
|
||||
if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterMeshDatasetGroups * >( parameterDefinition() )->meshLayerParameterName() )
|
||||
{
|
||||
setMeshLayerWrapperValue( wrapper );
|
||||
connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [ = ]
|
||||
{
|
||||
setMeshLayerWrapperValue( wrapper );
|
||||
} );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsProcessingGui::Modeler:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetGroupsWidgetWrapper::setMeshLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
|
||||
{
|
||||
if ( ! mWidget )
|
||||
return;
|
||||
|
||||
// evaluate value to layer
|
||||
QgsProcessingContext *context = nullptr;
|
||||
if ( mProcessingContextGenerator )
|
||||
context = mProcessingContextGenerator->processingContext();
|
||||
|
||||
bool layerFromProject;
|
||||
QgsMeshLayer *meshLayer;
|
||||
if ( !context )
|
||||
{
|
||||
QgsProcessingContext dummyContext;
|
||||
meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), dummyContext );
|
||||
layerFromProject = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), *context );
|
||||
layerFromProject = context->project() && context->project()->layerStore()->layers<QgsMeshLayer *>().contains( meshLayer );
|
||||
}
|
||||
|
||||
if ( mWidget )
|
||||
mWidget->setMeshLayer( meshLayer, layerFromProject );
|
||||
}
|
||||
|
||||
QWidget *QgsProcessingMeshDatasetGroupsWidgetWrapper::createWidget() SIP_FACTORY
|
||||
{
|
||||
mWidget = new QgsProcessingMeshDatasetGroupsWidget( nullptr, static_cast<const QgsProcessingParameterMeshDatasetGroups *>( parameterDefinition() ) );
|
||||
connect( mWidget, &QgsProcessingMeshDatasetGroupsWidget::changed, this, [ = ]
|
||||
{
|
||||
emit widgetValueHasChanged( this );
|
||||
} );
|
||||
|
||||
return mWidget;
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetGroupsWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
|
||||
{
|
||||
Q_UNUSED( context );
|
||||
if ( mWidget )
|
||||
mWidget->setValue( value );
|
||||
}
|
||||
|
||||
QVariant QgsProcessingMeshDatasetGroupsWidgetWrapper::widgetValue() const
|
||||
{
|
||||
if ( mWidget )
|
||||
return mWidget->value();
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
void QgsProcessingMeshDatasetGroupsWidget::updateSummaryText()
|
||||
{
|
||||
mLineEdit->setText( tr( "%1 options selected" ).arg( mValue.count() ) );
|
||||
}
|
||||
|
||||
QgsProcessingMeshDatasetTimeWidgetWrapper::QgsProcessingMeshDatasetTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter,
|
||||
QgsProcessingGui::WidgetType type,
|
||||
QWidget *parent )
|
||||
: QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString QgsProcessingMeshDatasetTimeWidgetWrapper::parameterType() const
|
||||
{
|
||||
return QgsProcessingParameterMeshDatasetTime::typeName();
|
||||
}
|
||||
|
||||
QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMeshDatasetTimeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
|
||||
{
|
||||
return new QgsProcessingMeshDatasetTimeWidgetWrapper( parameter, type );
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
|
||||
{
|
||||
QgsAbstractProcessingParameterWidgetWrapper::postInitialize( wrappers ); //necessary here?
|
||||
switch ( type() )
|
||||
{
|
||||
case QgsProcessingGui::Standard:
|
||||
case QgsProcessingGui::Batch:
|
||||
{
|
||||
const QgsAbstractProcessingParameterWidgetWrapper *layerParameterWrapper = nullptr;
|
||||
const QgsAbstractProcessingParameterWidgetWrapper *datasetGroupsParameterWrapper = nullptr;
|
||||
for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
|
||||
{
|
||||
if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterMeshDatasetTime * >( parameterDefinition() )->meshLayerParameterName() )
|
||||
layerParameterWrapper = wrapper;
|
||||
|
||||
if ( wrapper->parameterDefinition()->name() == static_cast< const QgsProcessingParameterMeshDatasetTime * >( parameterDefinition() )->datasetGroupParameterName() )
|
||||
datasetGroupsParameterWrapper = wrapper;
|
||||
}
|
||||
setMeshLayerWrapperValue( layerParameterWrapper );
|
||||
setDatasetGroupIndexesWrapperValue( datasetGroupsParameterWrapper );
|
||||
connect( datasetGroupsParameterWrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, [ = ]
|
||||
{
|
||||
setMeshLayerWrapperValue( layerParameterWrapper );
|
||||
setDatasetGroupIndexesWrapperValue( datasetGroupsParameterWrapper );
|
||||
} );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsProcessingGui::Modeler:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidgetWrapper::setMeshLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
|
||||
{
|
||||
if ( !mWidget )
|
||||
return;
|
||||
|
||||
// evaluate value to layer
|
||||
QgsProcessingContext *context = nullptr;
|
||||
if ( mProcessingContextGenerator )
|
||||
context = mProcessingContextGenerator->processingContext();
|
||||
|
||||
bool layerFromProject;
|
||||
QgsMeshLayer *meshLayer;
|
||||
if ( !context )
|
||||
{
|
||||
QgsProcessingContext dummyContext;
|
||||
meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), dummyContext );
|
||||
layerFromProject = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
meshLayer = QgsProcessingParameters::parameterAsMeshLayer( wrapper->parameterDefinition(), wrapper->parameterValue(), *context );
|
||||
layerFromProject = context->project() && context->project()->layerStore()->layers<QgsMeshLayer *>().contains( meshLayer );
|
||||
}
|
||||
|
||||
mWidget->setMeshLayer( meshLayer, layerFromProject );
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidgetWrapper::setDatasetGroupIndexesWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper )
|
||||
{
|
||||
if ( !mWidget )
|
||||
return;
|
||||
|
||||
QVariant datasetGroupsVariant = wrapper->parameterValue();
|
||||
|
||||
if ( !datasetGroupsVariant.isValid() || datasetGroupsVariant.type() != QVariant::List )
|
||||
mWidget->setDatasetGroupIndexes( QList<int>() );
|
||||
|
||||
QVariantList datasetGroupsListVariant = datasetGroupsVariant.toList();
|
||||
|
||||
QList<int> datasetGroupsIndexes;
|
||||
for ( const QVariant &variantIndex : datasetGroupsListVariant )
|
||||
datasetGroupsIndexes << variantIndex.toInt();
|
||||
|
||||
mWidget->setDatasetGroupIndexes( datasetGroupsIndexes );
|
||||
|
||||
}
|
||||
|
||||
QWidget *QgsProcessingMeshDatasetTimeWidgetWrapper::createWidget()
|
||||
{
|
||||
mWidget = new QgsProcessingMeshDatasetTimeWidget( nullptr, static_cast<const QgsProcessingParameterMeshDatasetTime *>( parameterDefinition() ), widgetContext() );
|
||||
|
||||
QgsMapCanvas *canvas = widgetContext().mapCanvas();
|
||||
if ( canvas )
|
||||
{
|
||||
connect( canvas, &QgsMapCanvas::temporalRangeChanged, mWidget, &QgsProcessingMeshDatasetTimeWidget::updateValue );
|
||||
}
|
||||
connect( mWidget, &QgsProcessingMeshDatasetTimeWidget::changed, this, [ = ]
|
||||
{
|
||||
emit widgetValueHasChanged( this );
|
||||
} );
|
||||
|
||||
return mWidget;
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
|
||||
{
|
||||
Q_UNUSED( context );
|
||||
if ( mWidget )
|
||||
mWidget->setValue( value );
|
||||
}
|
||||
|
||||
QVariant QgsProcessingMeshDatasetTimeWidgetWrapper::widgetValue() const
|
||||
{
|
||||
if ( mWidget )
|
||||
return mWidget->value();
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QgsProcessingMeshDatasetTimeWidget::QgsProcessingMeshDatasetTimeWidget( QWidget *parent,
|
||||
const QgsProcessingParameterMeshDatasetTime *param,
|
||||
const QgsProcessingParameterWidgetContext &context ):
|
||||
QWidget( parent ),
|
||||
mParam( param )
|
||||
{
|
||||
setupUi( this );
|
||||
|
||||
dateTimeEdit->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
|
||||
|
||||
mCanvas = context.mapCanvas();
|
||||
|
||||
connect( radioButtonCurrentCanvasTime, &QRadioButton::toggled, [this]( bool isChecked ) {if ( isChecked ) this->updateValue();} );
|
||||
connect( radioButtonDefinedDateTime, &QRadioButton::toggled, [this]( bool isChecked ) {if ( isChecked ) this->updateValue();} );
|
||||
connect( radioButtonDatasetGroupTimeStep, &QRadioButton::toggled, [this]( bool isChecked ) {if ( isChecked ) this->updateValue();} );
|
||||
connect( dateTimeEdit, &QgsDateTimeEdit::dateTimeChanged, this, &QgsProcessingMeshDatasetTimeWidget::updateValue );
|
||||
connect( comboBoxDatasetTimeStep, qgis::overload<int>::of( &QComboBox::currentIndexChanged ),
|
||||
this, &QgsProcessingMeshDatasetTimeWidget::updateValue );
|
||||
|
||||
updateWidget();
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidget::setMeshLayer( QgsMeshLayer *layer, bool layerFromProject )
|
||||
{
|
||||
if ( mMeshLayer == layer )
|
||||
return;
|
||||
|
||||
if ( layerFromProject )
|
||||
{
|
||||
mMeshLayer = layer;
|
||||
mReferenceTime = static_cast<QgsMeshLayerTemporalProperties *>( layer->temporalProperties() )->referenceTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
mMeshLayer = nullptr;
|
||||
mReferenceTime = layer->dataProvider()->temporalCapabilities()->referenceTime();
|
||||
storeTimeStepsFromLayer( layer );
|
||||
}
|
||||
|
||||
if ( mReferenceTime.isValid() )
|
||||
whileBlocking( dateTimeEdit )->setDateTime( mReferenceTime );
|
||||
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidget::setDatasetGroupIndexes( const QList<int> datasetGroupIndexes )
|
||||
{
|
||||
if ( datasetGroupIndexes == mDatasetGroupIndexes )
|
||||
return;
|
||||
mDatasetGroupIndexes = datasetGroupIndexes;
|
||||
populateTimeSteps();
|
||||
updateValue();
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidget::setValue( const QVariant &value )
|
||||
{
|
||||
if ( !value.isValid() || value.type() != QVariant::Map )
|
||||
return;
|
||||
|
||||
mValue = value.toMap();
|
||||
|
||||
if ( !mValue.contains( QStringLiteral( "type" ) ) || !mValue.contains( QStringLiteral( "value" ) ) )
|
||||
return;
|
||||
|
||||
QString type = mValue.value( QStringLiteral( "type" ) ).toString();
|
||||
|
||||
setEnabled( true );
|
||||
if ( type == QStringLiteral( "static" ) )
|
||||
{
|
||||
setEnabled( false );
|
||||
}
|
||||
else if ( type == QStringLiteral( "dataset-time-step" ) )
|
||||
{
|
||||
whileBlocking( radioButtonDatasetGroupTimeStep )->setChecked( true );
|
||||
whileBlocking( comboBoxDatasetTimeStep )->setCurrentIndex( comboBoxDatasetTimeStep->findData( mValue.value( QStringLiteral( "value" ) ) ) );
|
||||
}
|
||||
else if ( type == QStringLiteral( "dataset-time-step" ) )
|
||||
{
|
||||
radioButtonDefinedDateTime->setChecked( true );
|
||||
whileBlocking( dateTimeEdit )->setDate( mValue.value( QStringLiteral( "value" ) ).toDate() );
|
||||
}
|
||||
else if ( type == QStringLiteral( "current-context-time" ) )
|
||||
{
|
||||
whileBlocking( radioButtonCurrentCanvasTime )->setChecked( true );
|
||||
}
|
||||
|
||||
emit changed();
|
||||
updateWidget();
|
||||
}
|
||||
|
||||
QVariant QgsProcessingMeshDatasetTimeWidget::value() const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidget::updateWidget()
|
||||
{
|
||||
bool isStatic = !hasTemporalDataset();
|
||||
setEnabled( !isStatic );
|
||||
|
||||
if ( mCanvas != nullptr && mCanvas->mapSettings().isTemporal() )
|
||||
{
|
||||
whileBlocking( radioButtonCurrentCanvasTime )->setEnabled( true && mReferenceTime.isValid() );
|
||||
labelCurrentCanvasTime->setText( mCanvas->mapSettings().temporalRange().begin().toString( "yyyy-MM-dd HH:mm:ss" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
whileBlocking( radioButtonCurrentCanvasTime )->setEnabled( false );
|
||||
if ( radioButtonCurrentCanvasTime->isChecked() )
|
||||
whileBlocking( radioButtonDefinedDateTime )->setChecked( true );
|
||||
}
|
||||
|
||||
if ( ! mReferenceTime.isValid() )
|
||||
whileBlocking( radioButtonDatasetGroupTimeStep )->setChecked( true );
|
||||
|
||||
whileBlocking( radioButtonDefinedDateTime )->setEnabled( mReferenceTime.isValid() );
|
||||
|
||||
dateTimeEdit->setVisible( radioButtonDefinedDateTime->isChecked() && !isStatic );
|
||||
labelCurrentCanvasTime->setVisible( radioButtonCurrentCanvasTime->isChecked() && !isStatic );
|
||||
comboBoxDatasetTimeStep->setVisible( radioButtonDatasetGroupTimeStep->isChecked() && !isStatic );
|
||||
}
|
||||
|
||||
bool QgsProcessingMeshDatasetTimeWidget::hasTemporalDataset() const
|
||||
{
|
||||
for ( int index : mDatasetGroupIndexes )
|
||||
{
|
||||
if ( mMeshLayer && mMeshLayer->datasetGroupMetadata( index ).isTemporal() )
|
||||
return true;
|
||||
else if ( mDatasetTimeSteps.contains( index ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidget::populateTimeSteps()
|
||||
{
|
||||
if ( mMeshLayer )
|
||||
{
|
||||
populateTimeStepsFromLayer();
|
||||
return;
|
||||
}
|
||||
|
||||
QMap<quint64, QgsMeshDatasetIndex> timeStep;
|
||||
for ( int groupIndex : mDatasetGroupIndexes )
|
||||
{
|
||||
if ( !mDatasetTimeSteps.contains( groupIndex ) )
|
||||
continue;
|
||||
const QList<qint64> relativeTimeSteps = mDatasetTimeSteps.value( groupIndex );
|
||||
for ( int index = 0; index < relativeTimeSteps.count(); ++index )
|
||||
{
|
||||
QgsMeshDatasetIndex datasetIndex( groupIndex, index );
|
||||
if ( timeStep.contains( relativeTimeSteps.at( index ) ) )
|
||||
continue;
|
||||
timeStep[relativeTimeSteps.at( index )] = datasetIndex;
|
||||
}
|
||||
}
|
||||
|
||||
for ( qint64 key : timeStep.keys() )
|
||||
{
|
||||
QString stringTime = QgsMeshLayerUtils::formatTime( key / 1000 / 3600, mReferenceTime, QgsMeshTimeSettings() );
|
||||
QVariantList data;
|
||||
const QgsMeshDatasetIndex &index = timeStep.value( key );
|
||||
data << index.group() << index.dataset();
|
||||
whileBlocking( comboBoxDatasetTimeStep )->addItem( stringTime, data );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidget::populateTimeStepsFromLayer()
|
||||
{
|
||||
whileBlocking( comboBoxDatasetTimeStep )->clear();
|
||||
|
||||
if ( !mMeshLayer )
|
||||
return;
|
||||
|
||||
QMap<quint64, QgsMeshDatasetIndex> timeStep;
|
||||
for ( int groupIndex : mDatasetGroupIndexes )
|
||||
{
|
||||
QgsMeshDatasetGroupMetadata meta = mMeshLayer->datasetGroupMetadata( groupIndex );
|
||||
if ( !meta.isTemporal() )
|
||||
continue;
|
||||
int datasetCount = mMeshLayer->datasetCount( groupIndex );
|
||||
|
||||
for ( int index = 0; index < datasetCount; ++index )
|
||||
{
|
||||
QgsMeshDatasetIndex datasetIndex( groupIndex, index );
|
||||
qint64 relativeTime = mMeshLayer->datasetRelativeTimeInMilliseconds( datasetIndex );
|
||||
if ( timeStep.contains( relativeTime ) )
|
||||
continue;
|
||||
timeStep[relativeTime] = datasetIndex;
|
||||
}
|
||||
}
|
||||
|
||||
for ( qint64 key : timeStep.keys() )
|
||||
{
|
||||
QString stringTime = mMeshLayer->formatTime( key / 1000 / 3600 );
|
||||
QVariantList data;
|
||||
const QgsMeshDatasetIndex &index = timeStep.value( key );
|
||||
data << index.group() << index.dataset();
|
||||
whileBlocking( comboBoxDatasetTimeStep )->addItem( stringTime, data );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidget::storeTimeStepsFromLayer( QgsMeshLayer *layer )
|
||||
{
|
||||
mDatasetTimeSteps.clear();
|
||||
if ( !layer )
|
||||
return;
|
||||
QList<int> datasetGroupsList = layer->datasetGroupsIndexes();
|
||||
for ( int groupIndex : datasetGroupsList )
|
||||
{
|
||||
QgsMeshDatasetGroupMetadata meta = layer->datasetGroupMetadata( groupIndex );
|
||||
if ( !meta.isTemporal() )
|
||||
continue;
|
||||
int datasetCount = layer->datasetCount( groupIndex );
|
||||
QList<qint64> relativeTimeSteps;
|
||||
relativeTimeSteps.reserve( datasetCount );
|
||||
for ( int index = 0; index < datasetCount; ++index )
|
||||
relativeTimeSteps.append( layer->datasetRelativeTimeInMilliseconds( QgsMeshDatasetIndex( groupIndex, index ) ) );
|
||||
mDatasetTimeSteps[groupIndex] = relativeTimeSteps;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidget::buildValue()
|
||||
{
|
||||
mValue.clear();
|
||||
|
||||
if ( !isEnabled() )
|
||||
{
|
||||
mValue[QStringLiteral( "type" )] = QStringLiteral( "static" );
|
||||
}
|
||||
else if ( radioButtonDatasetGroupTimeStep->isChecked() )
|
||||
{
|
||||
mValue[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" );
|
||||
mValue[QStringLiteral( "value" )] = comboBoxDatasetTimeStep->currentData();
|
||||
}
|
||||
else if ( radioButtonDefinedDateTime->isChecked() )
|
||||
{
|
||||
mValue[QStringLiteral( "type" )] = QStringLiteral( "defined-date-time" );
|
||||
mValue[QStringLiteral( "value" )] = dateTimeEdit->dateTime();
|
||||
}
|
||||
else if ( radioButtonCurrentCanvasTime->isChecked() && mCanvas )
|
||||
{
|
||||
mValue[QStringLiteral( "type" )] = QStringLiteral( "current-context-time" );
|
||||
}
|
||||
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void QgsProcessingMeshDatasetTimeWidget::updateValue()
|
||||
{
|
||||
updateWidget();
|
||||
buildValue();
|
||||
}
|
||||
|
||||
///@endcond
|
183
src/gui/processing/qgsprocessingmeshdatasetwidget.h
Normal file
183
src/gui/processing/qgsprocessingmeshdatasetwidget.h
Normal file
@ -0,0 +1,183 @@
|
||||
/***************************************************************************
|
||||
qgsprocessingmeshdatasetwidget.h
|
||||
---------------------
|
||||
Date : October 2020
|
||||
Copyright : (C) 2020 by Vincent Cloarec
|
||||
Email : vcloarec at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSPROCESSINGMESHDATASETWIDGET_H
|
||||
#define QGSPROCESSINGMESHDATASETWIDGET_H
|
||||
|
||||
#include <QAction>
|
||||
|
||||
#include "qgsprocessingwidgetwrapperimpl.h"
|
||||
#include "qgsprocessingparametermeshdataset.h"
|
||||
|
||||
#include "ui_qgsprocessingmeshdatasettimewidget.h"
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
/// @cond PRIVATE
|
||||
|
||||
class GUI_EXPORT QgsProcessingMeshDatasetGroupsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsProcessingMeshDatasetGroupsWidget( QWidget *parent = nullptr, const QgsProcessingParameterMeshDatasetGroups *param = nullptr );
|
||||
|
||||
/**
|
||||
* Set the mesh layer for populate the dataset group names,
|
||||
* if \a layerFromProject is false, the layer will not stay referenced in the instance of this object but
|
||||
* all that is needed is stored in the instance
|
||||
*/
|
||||
void setMeshLayer( QgsMeshLayer *layer, bool layerFromProject = false );
|
||||
void setValue( const QVariant &value );
|
||||
QVariant value() const;
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
private slots:
|
||||
void showDialog();
|
||||
void selectCurrentActiveDatasetGroup();
|
||||
|
||||
private:
|
||||
const QgsProcessingParameterMeshDatasetGroups *mParam = nullptr;
|
||||
QVariantList mValue;
|
||||
|
||||
QPointer<QLineEdit> mLineEdit = nullptr;
|
||||
QPointer<QToolButton> mToolButton = nullptr;
|
||||
QPointer<QAction> mActionCurrentActiveDatasetGroups = nullptr;
|
||||
QPointer<QAction> mActionAvailableDatasetGroups = nullptr;
|
||||
QgsMeshLayer *mMeshLayer = nullptr;
|
||||
QMap<int, QString> mDatasetGroupsNames; //used to store the dataet groups name if layer is not referenced
|
||||
|
||||
QStringList datasetGroupsNames();
|
||||
void updateSummaryText();
|
||||
|
||||
friend class TestProcessingGui;
|
||||
};
|
||||
|
||||
|
||||
class GUI_EXPORT QgsProcessingMeshDatasetGroupsWidgetWrapper : public QgsAbstractProcessingParameterWidgetWrapper, public QgsProcessingParameterWidgetFactoryInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsProcessingMeshDatasetGroupsWidgetWrapper( const QgsProcessingParameterDefinition *parameter = nullptr,
|
||||
QgsProcessingGui::WidgetType type = QgsProcessingGui::Standard, QWidget *parent = nullptr );
|
||||
|
||||
QString parameterType() const override;
|
||||
QgsAbstractProcessingParameterWidgetWrapper *createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type ) override;
|
||||
void postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers ) override;
|
||||
|
||||
//! Sets the layer parameter widget wrapper
|
||||
void setMeshLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper );
|
||||
|
||||
protected:
|
||||
QStringList compatibleParameterTypes() const override {return QStringList();}
|
||||
QStringList compatibleOutputTypes() const override {return QStringList();}
|
||||
QWidget *createWidget() override;
|
||||
void setWidgetValue( const QVariant &value, QgsProcessingContext &context ) override;
|
||||
QVariant widgetValue() const override;
|
||||
|
||||
private:
|
||||
QgsProcessingMeshDatasetGroupsWidget *mWidget = nullptr;
|
||||
std::unique_ptr<QgsMeshLayer> mTemporarytMeshLayer;
|
||||
|
||||
friend class TestProcessingGui;
|
||||
};
|
||||
|
||||
|
||||
class GUI_EXPORT QgsProcessingMeshDatasetTimeWidget : public QWidget, private Ui::QgsProcessingMeshDatasetTimeWidgetBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsProcessingMeshDatasetTimeWidget( QWidget *parent = nullptr,
|
||||
const QgsProcessingParameterMeshDatasetTime *param = nullptr,
|
||||
const QgsProcessingParameterWidgetContext &context = QgsProcessingParameterWidgetContext() );
|
||||
|
||||
/**
|
||||
* Set the mesh layer for populate the time steps,
|
||||
* if \a layerFromProject is false, the layer will not stay referenced in the instance of this object but
|
||||
* all that is needed is stored in the instance
|
||||
*/
|
||||
void setMeshLayer( QgsMeshLayer *layer, bool layerFromProject = false );
|
||||
void setDatasetGroupIndexes( const QList<int> datasetGroupIndexes );
|
||||
|
||||
void setValue( const QVariant &value );
|
||||
QVariant value() const;
|
||||
|
||||
public slots:
|
||||
void updateValue();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
private:
|
||||
const QgsProcessingParameterMeshDatasetTime *mParam = nullptr;
|
||||
QVariantMap mValue;
|
||||
QgsMapCanvas *mCanvas;
|
||||
|
||||
QLineEdit *mLineEdit = nullptr;
|
||||
QToolButton *mToolButton = nullptr;
|
||||
QgsMeshLayer *mMeshLayer = nullptr;
|
||||
QList<int> mDatasetGroupIndexes;
|
||||
QDateTime mReferenceTime;
|
||||
|
||||
void populateTimeSteps();
|
||||
bool hasTemporalDataset() const;
|
||||
//! Populates diretly the time steps combo box with the referenced layer, used if layer comes from project
|
||||
void populateTimeStepsFromLayer();
|
||||
//! Stores the dataset time steps to use them later depending of chosen dataset groups (setDatasetGroupIndexes()), used if layer does not come from project
|
||||
void storeTimeStepsFromLayer( QgsMeshLayer *layer );
|
||||
QMap<int, QList<qint64>> mDatasetTimeSteps; //used if layer does not come from project
|
||||
|
||||
void updateWidget();
|
||||
void buildValue();
|
||||
|
||||
friend class TestProcessingGui;
|
||||
};
|
||||
|
||||
class GUI_EXPORT QgsProcessingMeshDatasetTimeWidgetWrapper : public QgsAbstractProcessingParameterWidgetWrapper, public QgsProcessingParameterWidgetFactoryInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsProcessingMeshDatasetTimeWidgetWrapper( const QgsProcessingParameterDefinition *parameter = nullptr,
|
||||
QgsProcessingGui::WidgetType type = QgsProcessingGui::Standard, QWidget *parent = nullptr );
|
||||
|
||||
QString parameterType() const override;
|
||||
QgsAbstractProcessingParameterWidgetWrapper *createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type ) override;
|
||||
void postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers ) override;
|
||||
|
||||
//! Sets the layer parameter widget wrapper
|
||||
void setMeshLayerWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper );
|
||||
|
||||
//! Sets the dataset group indexes widget wrapper
|
||||
void setDatasetGroupIndexesWrapperValue( const QgsAbstractProcessingParameterWidgetWrapper *wrapper );
|
||||
|
||||
protected:
|
||||
QStringList compatibleParameterTypes() const override {return QStringList();}
|
||||
QStringList compatibleOutputTypes() const override {return QStringList();}
|
||||
QWidget *createWidget() override;
|
||||
void setWidgetValue( const QVariant &value, QgsProcessingContext &context ) override;
|
||||
QVariant widgetValue() const override;
|
||||
|
||||
private:
|
||||
QgsProcessingMeshDatasetTimeWidget *mWidget = nullptr;
|
||||
std::unique_ptr<QgsMeshLayer> mTemporarytMeshLayer;
|
||||
friend class TestProcessingGui;
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
||||
#endif // QGSPROCESSINGMESHDATASETWIDGET_H
|
@ -1465,7 +1465,6 @@ class GUI_EXPORT QgsProcessingDateTimeWidgetWrapper : public QgsAbstractProcessi
|
||||
QVariant widgetValue() const override;
|
||||
|
||||
QStringList compatibleParameterTypes() const override;
|
||||
|
||||
QStringList compatibleOutputTypes() const override;
|
||||
QString modelerExpressionFormatString() const override;
|
||||
|
||||
|
72
src/ui/processing/qgsprocessingmeshdatasettimewidget.ui
Normal file
72
src/ui/processing/qgsprocessingmeshdatasettimewidget.ui
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsProcessingMeshDatasetTimeWidgetBase</class>
|
||||
<widget class="QWidget" name="QgsProcessingMeshDatasetTimeWidgetBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>465</width>
|
||||
<height>122</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonCurrentCanvasTime">
|
||||
<property name="text">
|
||||
<string>Current canvas time</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonDefinedDateTime">
|
||||
<property name="text">
|
||||
<string>Defined date/time</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonDatasetGroupTimeStep">
|
||||
<property name="text">
|
||||
<string>Dataset group time step</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBoxDatasetTimeStep"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDateTimeEdit" name="dateTimeEdit">
|
||||
<property name="calendarPopup">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="timeSpec">
|
||||
<enum>Qt::UTC</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelCurrentCanvasTime">
|
||||
<property name="text">
|
||||
<string>Current canvas time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -129,7 +129,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="p1">
|
||||
<layout class="QVBoxLayout" name="verticalLayoutP1">
|
||||
@ -556,8 +556,6 @@
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../images/images.qrc"/>
|
||||
<include location="../../images/images.qrc"/>
|
||||
<include location="../../images/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "qgsprocessingparameteraggregate.h"
|
||||
#include "qgsprocessingparametertininputlayers.h"
|
||||
#include "qgsprocessingparameterdxflayers.h"
|
||||
#include "qgsprocessingparametermeshdataset.h"
|
||||
#include "qgsdxfexport.h"
|
||||
|
||||
class DummyAlgorithm : public QgsProcessingAlgorithm
|
||||
@ -605,6 +606,8 @@ class TestQgsProcessing: public QObject
|
||||
void parameterFieldMapping();
|
||||
void parameterAggregate();
|
||||
void parameterTinInputLayers();
|
||||
void parameterMeshDatasetGroups();
|
||||
void parameterMeshDatasetTime();
|
||||
void parameterDxfLayers();
|
||||
void checkParamValues();
|
||||
void combineLayerExtent();
|
||||
@ -8014,6 +8017,140 @@ void TestQgsProcessing::parameterTinInputLayers()
|
||||
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterTinInputLayers('tin input layer', '')" ) );
|
||||
}
|
||||
|
||||
void TestQgsProcessing::parameterMeshDatasetGroups()
|
||||
{
|
||||
QgsProcessingContext context;
|
||||
QgsProject project;
|
||||
context.setProject( &project );
|
||||
|
||||
std::unique_ptr< QgsProcessingParameterMeshDatasetGroups> def( new QgsProcessingParameterMeshDatasetGroups( QStringLiteral( "dataset groups" ), QStringLiteral( "groups" ) ) );
|
||||
|
||||
QVERIFY( def->type() == QStringLiteral( "meshdatasetgroups" ) );
|
||||
QVERIFY( def->dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices );
|
||||
QVERIFY( !def->checkValueIsAcceptable( 1 ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( 1.0 ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "test" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << "a" << "b" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
|
||||
QVariantList groupsList;
|
||||
QVERIFY( !def->checkValueIsAcceptable( groupsList ) );
|
||||
groupsList.append( 0 );
|
||||
QVERIFY( def->checkValueIsAcceptable( groupsList ) );
|
||||
groupsList.append( 5 );
|
||||
QVERIFY( def->checkValueIsAcceptable( groupsList ) );
|
||||
|
||||
QVERIFY( def->dependsOnOtherParameters().isEmpty() );
|
||||
|
||||
QString valueAsPythonString = def->valueAsPythonString( groupsList, context );
|
||||
QCOMPARE( valueAsPythonString, QStringLiteral( "[0,5]" ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsList ), QList<int>() << 0 << 5 );
|
||||
|
||||
QString pythonCode = def->asPythonString();
|
||||
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterMeshDatasetGroups('dataset groups', 'groups', dataType=QgsMeshDatasetGroupMetadata.DataOnVertices)" ) );
|
||||
|
||||
// optional, layer parameter and data on faces
|
||||
def.reset( new QgsProcessingParameterMeshDatasetGroups(
|
||||
QStringLiteral( "dataset groups" ),
|
||||
QStringLiteral( "groups" ),
|
||||
QStringLiteral( "layer parameter" ),
|
||||
QgsMeshDatasetGroupMetadata::DataOnFaces, true ) );
|
||||
QVERIFY( def->dataType() == QgsMeshDatasetGroupMetadata::DataOnFaces );
|
||||
QVERIFY( !def->checkValueIsAcceptable( 1 ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( 1.0 ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "test" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << "a" << "b" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "" ) );
|
||||
QVERIFY( def->checkValueIsAcceptable( QVariant() ) );
|
||||
groupsList = QVariantList();
|
||||
QVERIFY( def->checkValueIsAcceptable( groupsList ) );
|
||||
groupsList.append( 2 );
|
||||
QVERIFY( def->checkValueIsAcceptable( groupsList ) );
|
||||
groupsList.append( 6 );
|
||||
QVERIFY( def->checkValueIsAcceptable( groupsList ) );
|
||||
|
||||
valueAsPythonString = def->valueAsPythonString( groupsList, context );
|
||||
QCOMPARE( valueAsPythonString, QStringLiteral( "[2,6]" ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsList ), QList<int>() << 2 << 6 );
|
||||
|
||||
QVERIFY( !def->dependsOnOtherParameters().isEmpty() );
|
||||
QCOMPARE( def->meshLayerParameterName(), QStringLiteral( "layer parameter" ) );
|
||||
|
||||
pythonCode = def->asPythonString();
|
||||
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterMeshDatasetGroups('dataset groups', 'groups', meshLayerParameterName='layer parameter', dataType=QgsMeshDatasetGroupMetadata.DataOnFaces, optional=True)" ) );
|
||||
}
|
||||
|
||||
void TestQgsProcessing::parameterMeshDatasetTime()
|
||||
{
|
||||
QgsProcessingContext context;
|
||||
QgsProject project;
|
||||
context.setProject( &project );
|
||||
|
||||
std::unique_ptr< QgsProcessingParameterMeshDatasetTime> def( new QgsProcessingParameterMeshDatasetTime( QStringLiteral( "dataset groups" ), QStringLiteral( "groups" ) ) );
|
||||
QVERIFY( def->type() == QStringLiteral( "meshdatasettime" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( 1 ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( 1.0 ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "test" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << "a" << "b" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( "" ) );
|
||||
QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
|
||||
|
||||
QVariantMap value;
|
||||
value[QStringLiteral( "test" )] = QStringLiteral( "test" );
|
||||
QVERIFY( !def->checkValueIsAcceptable( value ) );
|
||||
|
||||
value.clear();
|
||||
value[QStringLiteral( "type" )] = QStringLiteral( "test" );
|
||||
QVERIFY( !def->checkValueIsAcceptable( value ) );
|
||||
|
||||
value[QStringLiteral( "type" )] = QStringLiteral( "static" );
|
||||
QVERIFY( def->checkValueIsAcceptable( value ) );
|
||||
QCOMPARE( def->valueAsPythonString( value, context ), QStringLiteral( "{'type': 'static'}" ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( value ), QStringLiteral( "static" ) );
|
||||
|
||||
|
||||
value[QStringLiteral( "type" )] = QStringLiteral( "current-context-time" );
|
||||
QVERIFY( def->checkValueIsAcceptable( value ) );
|
||||
QCOMPARE( def->valueAsPythonString( value, context ), QStringLiteral( "{'type': 'current-context-time'}" ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( value ), QStringLiteral( "current-context-time" ) );
|
||||
|
||||
value[QStringLiteral( "type" )] = QStringLiteral( "defined-date-time" );
|
||||
QVERIFY( !def->checkValueIsAcceptable( value ) );
|
||||
value[QStringLiteral( "value" )] = QDateTime( QDate( 2123, 1, 2 ), QTime( 1, 2, 3 ) );
|
||||
QVERIFY( def->checkValueIsAcceptable( value ) );
|
||||
QCOMPARE( def->valueAsPythonString( value, context ), QStringLiteral( "{'type': 'defined-date-time','value': QDateTime(QDate(2123, 1, 2), QTime(1, 2, 3))}" ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( value ), QStringLiteral( "defined-date-time" ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::timeValueAsDefinedDateTime( value ), QDateTime( QDate( 2123, 1, 2 ), QTime( 1, 2, 3 ) ) );
|
||||
QVERIFY( !QgsProcessingParameterMeshDatasetTime::timeValueAsDatasetIndex( value ).isValid() );
|
||||
|
||||
value.clear();
|
||||
value[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" );
|
||||
QVERIFY( !def->checkValueIsAcceptable( value ) );
|
||||
value[QStringLiteral( "value" )] = QVariantList() << 1 << 5;
|
||||
QVERIFY( def->checkValueIsAcceptable( value ) );
|
||||
QCOMPARE( def->valueAsPythonString( value, context ), QStringLiteral( "{'type': 'dataset-time-step','value': QgsMeshDatasetIndex(1,5)}" ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( value ), QStringLiteral( "dataset-time-step" ) );
|
||||
QVERIFY( !QgsProcessingParameterMeshDatasetTime::timeValueAsDefinedDateTime( value ).isValid() );
|
||||
QVERIFY( QgsProcessingParameterMeshDatasetTime::timeValueAsDatasetIndex( value ) == QgsMeshDatasetIndex( 1, 5 ) );
|
||||
|
||||
QString pythonCode = def->asPythonString();
|
||||
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterMeshDatasetTime('dataset groups', 'groups')" ) );
|
||||
|
||||
QVERIFY( def->dependsOnOtherParameters().isEmpty() );
|
||||
|
||||
def.reset( new QgsProcessingParameterMeshDatasetTime( QStringLiteral( "dataset groups" ), QStringLiteral( "groups" ), QStringLiteral( "layer parameter" ), QStringLiteral( "dataset group parameter" ) ) );
|
||||
pythonCode = def->asPythonString();
|
||||
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterMeshDatasetTime('dataset groups', 'groups', meshLayerParameterName='layer parameter', datasetGroupParameterName='dataset group parameter')" ) );
|
||||
|
||||
QVERIFY( !def->dependsOnOtherParameters().isEmpty() );
|
||||
QCOMPARE( def->meshLayerParameterName(), QStringLiteral( "layer parameter" ) );
|
||||
QCOMPARE( def->datasetGroupParameterName(), QStringLiteral( "dataset group parameter" ) );
|
||||
}
|
||||
|
||||
void TestQgsProcessing::parameterDateTime()
|
||||
{
|
||||
QgsProcessingContext context;
|
||||
@ -11160,6 +11297,7 @@ void TestQgsProcessing::variantToPythonLiteral()
|
||||
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QStringLiteral( "a 'string'" ) ), QStringLiteral( "'a \\'string\\''" ) );
|
||||
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QStringLiteral( "a \"string\"" ) ), QStringLiteral( "'a \\\"string\\\"'" ) );
|
||||
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QStringLiteral( "a \n str\tin\\g" ) ), QStringLiteral( "'a \\n str\\tin\\\\g'" ) );
|
||||
QCOMPARE( QgsProcessingUtils::variantToPythonLiteral( QDateTime( QDate( 2345, 1, 2 ), QTime( 6, 57, 58 ) ) ), QStringLiteral( "QDateTime(QDate(2345, 1, 2), QTime(6, 57, 58))" ) );
|
||||
QVariantMap map;
|
||||
map.insert( QStringLiteral( "list" ), QVariantList() << 1 << 2 << "a" );
|
||||
map.insert( QStringLiteral( "another" ), 4 );
|
||||
@ -11176,6 +11314,8 @@ void TestQgsProcessing::stringToPythonLiteral()
|
||||
QCOMPARE( QgsProcessingUtils::stringToPythonLiteral( QStringLiteral( "a \n str\tin\\g" ) ), QStringLiteral( "'a \\n str\\tin\\\\g'" ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TestQgsProcessing::defaultExtensionsForProvider()
|
||||
{
|
||||
DummyProvider3 provider;
|
||||
|
@ -149,6 +149,7 @@ class TestQgsProcessingAlgs: public QObject
|
||||
void exportAtlasLayoutPng();
|
||||
|
||||
void tinMeshCreation();
|
||||
void exportMeshVertices();
|
||||
|
||||
private:
|
||||
|
||||
@ -227,6 +228,19 @@ void TestQgsProcessingAlgs::initTestCase()
|
||||
QgsProject::instance()->addMapLayers(
|
||||
QList<QgsMapLayer *>() << mPolygonLayer );
|
||||
QVERIFY( mPolygonLayer->isValid() );
|
||||
|
||||
//add a mesh layer
|
||||
QString uri( dataDir + "/mesh/quad_and_triangle.2dm" );
|
||||
QString meshLayerName = QStringLiteral( "mesh layer" );
|
||||
QgsMeshLayer *meshLayer = new QgsMeshLayer( uri, meshLayerName, QStringLiteral( "mdal" ) );
|
||||
// Register the layer with the registry
|
||||
QgsProject::instance()->addMapLayer( meshLayer );
|
||||
QVERIFY( meshLayer->isValid() );
|
||||
meshLayer->addDatasets( dataDir + "/mesh/quad_and_triangle_vertex_scalar.dat" );
|
||||
meshLayer->addDatasets( dataDir + "/mesh/quad_and_triangle_vertex_vector.dat" );
|
||||
meshLayer->addDatasets( dataDir + "/mesh/quad_and_triangle_els_face_scalar.dat" );
|
||||
meshLayer->addDatasets( dataDir + "/mesh/quad_and_triangle_els_face_vector.dat" );
|
||||
QCOMPARE( meshLayer->datasetGroupCount(), 5 );
|
||||
}
|
||||
|
||||
void TestQgsProcessingAlgs::cleanupTestCase()
|
||||
@ -4797,6 +4811,89 @@ void TestQgsProcessingAlgs::tinMeshCreation()
|
||||
QVERIFY( qgsDoubleNear( meshLayer.datasetValue( QgsMeshDatasetIndex( 0, 0 ), QgsPointXY( -86.0, 35.0 ) ).scalar(), 1.855, 0.001 ) ) ;
|
||||
}
|
||||
|
||||
void TestQgsProcessingAlgs::exportMeshVertices()
|
||||
{
|
||||
std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:exportmeshvertices" ) ) );
|
||||
QVERIFY( alg != nullptr );
|
||||
|
||||
QVariantMap parameters;
|
||||
parameters.insert( QStringLiteral( "INPUT" ), "mesh layer" );
|
||||
|
||||
QVariantList datasetGroup;
|
||||
datasetGroup << 1 << 2;
|
||||
parameters.insert( QStringLiteral( "DATASET_GROUPS" ), datasetGroup );
|
||||
|
||||
QVariantMap datasetTime;
|
||||
datasetTime[QStringLiteral( "type" )] = QStringLiteral( "dataset-time-step" );
|
||||
QVariantList datasetIndex;
|
||||
datasetIndex << 1 << 1;
|
||||
datasetTime[QStringLiteral( "value" )] = datasetIndex;
|
||||
parameters.insert( QStringLiteral( "DATASET_TIME" ), datasetTime );
|
||||
|
||||
parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT );
|
||||
parameters.insert( QStringLiteral( "VECTOR_OPTION" ), 2 );
|
||||
|
||||
std::unique_ptr< QgsProcessingContext > context = qgis::make_unique< QgsProcessingContext >();
|
||||
context->setProject( QgsProject::instance() );
|
||||
QgsProcessingFeedback feedback;
|
||||
QVariantMap results;
|
||||
bool ok = false;
|
||||
results = alg->run( parameters, *context, &feedback, &ok );
|
||||
QVERIFY( ok );
|
||||
|
||||
QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) );
|
||||
QVERIFY( resultLayer );
|
||||
QVERIFY( resultLayer->isValid() );
|
||||
QVERIFY( resultLayer->geometryType() == QgsWkbTypes::PointGeometry );
|
||||
QCOMPARE( resultLayer->featureCount(), 5l );
|
||||
QgsAttributeList attributeList = resultLayer->attributeList();
|
||||
QCOMPARE( resultLayer->fields().count(), 5 );
|
||||
QCOMPARE( resultLayer->fields().at( 0 ).name(), QStringLiteral( "VertexScalarDataset" ) );
|
||||
QCOMPARE( resultLayer->fields().at( 1 ).name(), QStringLiteral( "VertexVectorDataset_x" ) );
|
||||
QCOMPARE( resultLayer->fields().at( 2 ).name(), QStringLiteral( "VertexVectorDataset_y" ) );
|
||||
QCOMPARE( resultLayer->fields().at( 3 ).name(), QStringLiteral( "VertexVectorDataset_mag" ) );
|
||||
QCOMPARE( resultLayer->fields().at( 4 ).name(), QStringLiteral( "VertexVectorDataset_dir" ) );
|
||||
|
||||
QgsFeatureIterator featIt = resultLayer->getFeatures();
|
||||
QgsFeature feat;
|
||||
featIt.nextFeature( feat );
|
||||
QCOMPARE( QStringLiteral( "PointZ (1000 2000 20)" ), feat.geometry().asWkt() );
|
||||
QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 );
|
||||
QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 );
|
||||
QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.828, 2 ) );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45.0, 2 ) );
|
||||
|
||||
featIt.nextFeature( feat );
|
||||
QCOMPARE( QStringLiteral( "PointZ (2000 2000 30)" ), feat.geometry().asWkt() );
|
||||
QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 );
|
||||
QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 );
|
||||
QCOMPARE( feat.attributes().at( 2 ).toDouble(), 2.0 );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 3.605, 2 ) );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 56.3099, 2 ) );
|
||||
featIt.nextFeature( feat );
|
||||
QCOMPARE( QStringLiteral( "PointZ (3000 2000 40)" ), feat.geometry().asWkt() );
|
||||
QCOMPARE( feat.attributes().at( 0 ).toDouble(), 4.0 );
|
||||
QCOMPARE( feat.attributes().at( 1 ).toDouble(), 4.0 );
|
||||
QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 5.0, 2 ) );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 53.130, 2 ) );
|
||||
featIt.nextFeature( feat );
|
||||
QCOMPARE( QStringLiteral( "PointZ (2000 3000 50)" ), feat.geometry().asWkt() );
|
||||
QCOMPARE( feat.attributes().at( 0 ).toDouble(), 3.0 );
|
||||
QCOMPARE( feat.attributes().at( 1 ).toDouble(), 3.0 );
|
||||
QCOMPARE( feat.attributes().at( 2 ).toDouble(), 3.0 );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 4.242, 2 ) );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 45, 2 ) );
|
||||
featIt.nextFeature( feat );
|
||||
QCOMPARE( QStringLiteral( "PointZ (1000 3000 10)" ), feat.geometry().asWkt() );
|
||||
QCOMPARE( feat.attributes().at( 0 ).toDouble(), 2.0 );
|
||||
QCOMPARE( feat.attributes().at( 1 ).toDouble(), 2.0 );
|
||||
QCOMPARE( feat.attributes().at( 2 ).toDouble(), -1.0 );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 3 ).toDouble(), 2.236, 2 ) );
|
||||
QVERIFY( qgsDoubleNearSig( feat.attributes().at( 4 ).toDouble(), 116.565, 2 ) );
|
||||
}
|
||||
|
||||
bool TestQgsProcessingAlgs::imageCheck( const QString &testName, const QString &renderedImage )
|
||||
{
|
||||
QgsRenderChecker checker;
|
||||
|
@ -668,7 +668,7 @@ void TestQgsMapToolIdentifyAction::identifyMesh()
|
||||
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Scalar Value" )], QStringLiteral( "42" ) );
|
||||
QCOMPARE( results[0].mDerivedAttributes[QStringLiteral( "Source" )], mesh );
|
||||
|
||||
QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Time Step" )], QStringLiteral( "01.01.1950 00:00:00" ) );
|
||||
QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Time Step" )], QStringLiteral( "1950-01-01 00:00:00" ) );
|
||||
|
||||
QCOMPARE( results[1].mLabel, QStringLiteral( "VertexVectorDataset" ) );
|
||||
QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Source" )], vectorDs );
|
||||
|
@ -80,6 +80,7 @@
|
||||
#include "qgsprocessingfeaturesourceoptionswidget.h"
|
||||
#include "qgsextentwidget.h"
|
||||
#include "qgsrasterbandcombobox.h"
|
||||
#include "qgsmeshlayertemporalproperties.h"
|
||||
#include "qgsmodelgraphicsscene.h"
|
||||
#include "qgsmodelgraphicsview.h"
|
||||
#include "qgsmodelcomponentgraphicitem.h"
|
||||
@ -91,6 +92,7 @@
|
||||
#include "qgsprocessingtininputlayerswidget.h"
|
||||
#include "qgsprocessingparameterdxflayers.h"
|
||||
#include "qgsprocessingdxflayerswidgetwrapper.h"
|
||||
#include "qgsprocessingmeshdatasetwidget.h"
|
||||
|
||||
|
||||
class TestParamType : public QgsProcessingParameterDefinition
|
||||
@ -254,6 +256,8 @@ class TestProcessingGui : public QObject
|
||||
void testFolderOutWrapper();
|
||||
void testTinInputLayerWrapper();
|
||||
void testDxfLayersWrapper();
|
||||
void testMeshDatasetWrapperLayerInProject();
|
||||
void testMeshDatasetWrapperLayerOutsideProject();
|
||||
void testModelGraphicsView();
|
||||
|
||||
private:
|
||||
@ -8907,6 +8911,311 @@ void TestProcessingGui::testDxfLayersWrapper()
|
||||
QCOMPARE( valueAsPythonString, QStringLiteral( "[{'layer': '%1','attributeIndex': -1}]" ).arg( vectorLayer->source() ) );
|
||||
}
|
||||
|
||||
void TestProcessingGui::testMeshDatasetWrapperLayerInProject()
|
||||
{
|
||||
QgsProcessingParameterMeshLayer layerDefinition( QStringLiteral( "layer" ), QStringLiteral( "layer" ) );
|
||||
QgsProcessingMeshLayerWidgetWrapper layerWrapper( &layerDefinition );
|
||||
|
||||
QgsProcessingParameterMeshDatasetGroups groupsDefinition( QStringLiteral( "groups" ),
|
||||
QStringLiteral( "groups" ),
|
||||
QStringLiteral( "layer" ),
|
||||
QgsMeshDatasetGroupMetadata::DataOnVertices );
|
||||
QgsProcessingMeshDatasetGroupsWidgetWrapper groupsWrapper( &groupsDefinition );
|
||||
|
||||
QgsProcessingParameterMeshDatasetTime timeDefinition( QStringLiteral( "time" ), QStringLiteral( "time" ), QStringLiteral( "layer" ), QStringLiteral( "groups" ) );
|
||||
QgsProcessingMeshDatasetTimeWidgetWrapper timeWrapper( &timeDefinition );
|
||||
|
||||
QList<QgsAbstractProcessingParameterWidgetWrapper *> wrappers;
|
||||
wrappers << &layerWrapper << &groupsWrapper << &timeWrapper;
|
||||
|
||||
QgsProject project;
|
||||
QgsProcessingContext context;
|
||||
context.setProject( &project );
|
||||
QgsProcessingParameterWidgetContext widgetContext;
|
||||
std::unique_ptr<QgsMapCanvas> mapCanvas = qgis::make_unique<QgsMapCanvas>();
|
||||
widgetContext.setMapCanvas( mapCanvas.get() );
|
||||
|
||||
widgetContext.setProject( &project );
|
||||
layerWrapper.setWidgetContext( widgetContext );
|
||||
groupsWrapper.setWidgetContext( widgetContext );
|
||||
timeWrapper.setWidgetContext( widgetContext );
|
||||
|
||||
TestProcessingContextGenerator generator( context );
|
||||
layerWrapper.registerProcessingContextGenerator( &generator );
|
||||
groupsWrapper.registerProcessingContextGenerator( &generator );
|
||||
timeWrapper.registerProcessingContextGenerator( &generator );
|
||||
|
||||
|
||||
QSignalSpy layerSpy( &layerWrapper, &QgsProcessingMeshLayerWidgetWrapper::widgetValueHasChanged );
|
||||
QSignalSpy groupsSpy( &groupsWrapper, &QgsProcessingMeshDatasetGroupsWidgetWrapper::widgetValueHasChanged );
|
||||
QSignalSpy timeSpy( &timeWrapper, &QgsProcessingMeshDatasetTimeWidgetWrapper::widgetValueHasChanged );
|
||||
|
||||
std::unique_ptr<QWidget> layerWidget( layerWrapper.createWrappedWidget( context ) );
|
||||
std::unique_ptr<QWidget> groupWidget( groupsWrapper.createWrappedWidget( context ) );
|
||||
std::unique_ptr<QWidget> timeWidget( timeWrapper.createWrappedWidget( context ) );
|
||||
QgsProcessingMeshDatasetGroupsWidget *datasetGroupWidget = qobject_cast<QgsProcessingMeshDatasetGroupsWidget *>( groupWidget.get() );
|
||||
QgsProcessingMeshDatasetTimeWidget *datasetTimeWidget = qobject_cast<QgsProcessingMeshDatasetTimeWidget *>( timeWidget.get() );
|
||||
|
||||
QVERIFY( layerWidget );
|
||||
QVERIFY( groupWidget );
|
||||
QVERIFY( datasetGroupWidget );
|
||||
QVERIFY( timeWidget );
|
||||
|
||||
groupsWrapper.postInitialize( wrappers );
|
||||
timeWrapper.postInitialize( wrappers );
|
||||
|
||||
QString dataDir = QString( TEST_DATA_DIR ); //defined in CmakeLists.txt
|
||||
dataDir += "/mesh";
|
||||
QString uri( dataDir + "/quad_and_triangle.2dm" );
|
||||
QString meshLayerName = QStringLiteral( "mesh layer" );
|
||||
QgsMeshLayer *layer = new QgsMeshLayer( uri, meshLayerName, QStringLiteral( "mdal" ) );
|
||||
QVERIFY( layer->isValid() );
|
||||
layer->addDatasets( dataDir + "/quad_and_triangle_vertex_scalar.dat" );
|
||||
layer->addDatasets( dataDir + "/quad_and_triangle_vertex_vector.dat" );
|
||||
layer->addDatasets( dataDir + "/quad_and_triangle_els_face_scalar.dat" );
|
||||
layer->addDatasets( dataDir + "/quad_and_triangle_els_face_vector.dat" );
|
||||
QgsMeshRendererSettings settings = layer->rendererSettings();
|
||||
// 1 dataset on vertices and 1 dataset on faces
|
||||
settings.setActiveScalarDatasetGroup( 1 );
|
||||
settings.setActiveVectorDatasetGroup( 4 );
|
||||
layer->setRendererSettings( settings );
|
||||
QCOMPARE( layer->datasetGroupCount(), 5 );
|
||||
|
||||
layerSpy.clear();
|
||||
groupsSpy.clear();
|
||||
timeSpy.clear();
|
||||
|
||||
// without layer in the project
|
||||
QString meshOutOfProject( dataDir + "/trap_steady_05_3D.nc" );
|
||||
layerWrapper.setWidgetValue( meshOutOfProject, context );
|
||||
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 1 );
|
||||
QCOMPARE( timeSpy.count(), 1 );
|
||||
|
||||
QVERIFY( datasetTimeWidget->radioButtonDatasetGroupTimeStep->isChecked() );
|
||||
|
||||
QVariantList groups;
|
||||
groups << 0;
|
||||
groupsWrapper.setWidgetValue( groups, context );
|
||||
QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsWrapper.widgetValue() ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsWrapper.widgetValue() ), QList<int>() << 0 );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "static" ) );
|
||||
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 2 );
|
||||
QCOMPARE( timeSpy.count(), 3 );
|
||||
|
||||
// with layer in the project
|
||||
layerSpy.clear();
|
||||
groupsSpy.clear();
|
||||
timeSpy.clear();
|
||||
|
||||
project.addMapLayer( layer );
|
||||
static_cast<QgsMeshLayerTemporalProperties *>( layer->temporalProperties() )->setReferenceTime(
|
||||
QDateTime( QDate( 2020, 01, 01 ), QTime( 0, 0, 0 ), Qt::UTC ), layer->dataProvider()->temporalCapabilities() );
|
||||
layerWrapper.setWidgetValue( meshLayerName, context );
|
||||
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 1 );
|
||||
QCOMPARE( timeSpy.count(), 2 );
|
||||
|
||||
datasetGroupWidget->selectCurrentActiveDatasetGroup();
|
||||
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 2 );
|
||||
QCOMPARE( timeSpy.count(), 3 );
|
||||
|
||||
QVariant groupsValue = groupsWrapper.widgetValue();
|
||||
QVERIFY( groupsValue.type() == QVariant::List );
|
||||
QVariantList groupsList = groupsValue.toList();
|
||||
QCOMPARE( groupsList.count(), 1 );
|
||||
QCOMPARE( groupsList.at( 0 ).toInt(), 1 );
|
||||
QString pythonString = groupsDefinition.valueAsPythonString( groupsValue, context );
|
||||
QCOMPARE( pythonString, QStringLiteral( "[1]" ) );
|
||||
QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsValue ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsValue ), QList<int>( {1} ) );
|
||||
|
||||
// 2 datasets on vertices
|
||||
settings = layer->rendererSettings();
|
||||
settings.setActiveVectorDatasetGroup( 2 );
|
||||
layer->setRendererSettings( settings );
|
||||
datasetGroupWidget->selectCurrentActiveDatasetGroup();
|
||||
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 3 );
|
||||
QCOMPARE( timeSpy.count(), 4 );
|
||||
|
||||
pythonString = groupsDefinition.valueAsPythonString( groupsWrapper.widgetValue(), context );
|
||||
QCOMPARE( pythonString, QStringLiteral( "[1,2]" ) );
|
||||
QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsWrapper.widgetValue() ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsWrapper.widgetValue() ), QList<int>() << 1 << 2 );
|
||||
|
||||
datasetTimeWidget->radioButtonDatasetGroupTimeStep->setChecked( true );
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 3 );
|
||||
QCOMPARE( timeSpy.count(), 4 ); //radioButtonDatasetGroupTimeStep already checked
|
||||
|
||||
QVariant timeValue = timeWrapper.widgetValue();
|
||||
QVERIFY( timeValue.type() == QVariant::Map );
|
||||
QVariantMap timeValueMap = timeValue.toMap();
|
||||
QCOMPARE( timeValueMap[QStringLiteral( "type" )].toString(), QStringLiteral( "dataset-time-step" ) );
|
||||
pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
|
||||
QCOMPARE( pythonString, QStringLiteral( "{'type': 'dataset-time-step','value': QgsMeshDatasetIndex(1,0)}" ) );
|
||||
QVERIFY( timeDefinition.checkValueIsAcceptable( timeValue ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeValue ), QStringLiteral( "dataset-time-step" ) );
|
||||
QVERIFY( QgsProcessingParameterMeshDatasetTime::timeValueAsDatasetIndex( timeValue ) == QgsMeshDatasetIndex( 1, 0 ) );
|
||||
|
||||
datasetTimeWidget->radioButtonDefinedDateTime->setChecked( true );
|
||||
QDateTime dateTime = QDateTime( QDate( 2020, 1, 1 ), QTime( 0, 1, 0 ), Qt::UTC );
|
||||
datasetTimeWidget->dateTimeEdit->setDateTime( dateTime );
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 3 );
|
||||
QCOMPARE( timeSpy.count(), 6 );
|
||||
pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
|
||||
QCOMPARE( pythonString, QStringLiteral( "{'type': 'defined-date-time','value': QDateTime(QDate(2020, 1, 1), QTime(0, 1, 0))}" ) );
|
||||
QVERIFY( timeDefinition.checkValueIsAcceptable( timeWrapper.widgetValue() ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "defined-date-time" ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::timeValueAsDefinedDateTime( timeWrapper.widgetValue() ), dateTime );
|
||||
|
||||
QVERIFY( !datasetTimeWidget->radioButtonCurrentCanvasTime->isEnabled() );
|
||||
mapCanvas->setTemporalRange( QgsDateTimeRange( QDateTime( QDate( 2021, 1, 1 ), QTime( 0, 3, 0 ), Qt::UTC ), QDateTime( QDate( 2020, 1, 1 ), QTime( 0, 5, 0 ), Qt::UTC ) ) );
|
||||
QVERIFY( datasetTimeWidget->radioButtonCurrentCanvasTime->isEnabled() );
|
||||
|
||||
datasetTimeWidget->radioButtonCurrentCanvasTime->setChecked( true );
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 3 );
|
||||
QCOMPARE( timeSpy.count(), 8 );
|
||||
pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
|
||||
QCOMPARE( pythonString, QStringLiteral( "{'type': 'current-context-time'}" ) );
|
||||
QVERIFY( timeDefinition.checkValueIsAcceptable( timeWrapper.widgetValue() ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "current-context-time" ) );
|
||||
|
||||
// 0 dataset on vertices
|
||||
settings = layer->rendererSettings();
|
||||
settings.setActiveScalarDatasetGroup( -1 );
|
||||
settings.setActiveVectorDatasetGroup( -1 );
|
||||
layer->setRendererSettings( settings );
|
||||
datasetGroupWidget->selectCurrentActiveDatasetGroup();
|
||||
QVERIFY( !datasetTimeWidget->isEnabled() );
|
||||
pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
|
||||
QCOMPARE( pythonString, QStringLiteral( "{'type': 'static'}" ) );
|
||||
QVERIFY( timeDefinition.checkValueIsAcceptable( timeWrapper.widgetValue() ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "static" ) );
|
||||
|
||||
// 1 static dataset on vertices
|
||||
settings = layer->rendererSettings();
|
||||
settings.setActiveScalarDatasetGroup( 0 );
|
||||
settings.setActiveVectorDatasetGroup( -1 );
|
||||
layer->setRendererSettings( settings );
|
||||
datasetGroupWidget->selectCurrentActiveDatasetGroup();
|
||||
QVERIFY( !datasetTimeWidget->isEnabled() );
|
||||
pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
|
||||
QCOMPARE( pythonString, QStringLiteral( "{'type': 'static'}" ) );
|
||||
QVERIFY( timeDefinition.checkValueIsAcceptable( timeWrapper.widgetValue() ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "static" ) );
|
||||
}
|
||||
|
||||
void TestProcessingGui::testMeshDatasetWrapperLayerOutsideProject()
|
||||
{
|
||||
QgsProcessingParameterMeshLayer layerDefinition( QStringLiteral( "layer" ), QStringLiteral( "layer" ) );
|
||||
QgsProcessingMeshLayerWidgetWrapper layerWrapper( &layerDefinition );
|
||||
|
||||
QgsProcessingParameterMeshDatasetGroups groupsDefinition( QStringLiteral( "groups" ),
|
||||
QStringLiteral( "groups" ),
|
||||
QStringLiteral( "layer" ),
|
||||
QgsMeshDatasetGroupMetadata::DataOnFaces );
|
||||
QgsProcessingMeshDatasetGroupsWidgetWrapper groupsWrapper( &groupsDefinition );
|
||||
|
||||
QgsProcessingParameterMeshDatasetTime timeDefinition( QStringLiteral( "time" ), QStringLiteral( "time" ), QStringLiteral( "layer" ), QStringLiteral( "groups" ) );
|
||||
QgsProcessingMeshDatasetTimeWidgetWrapper timeWrapper( &timeDefinition );
|
||||
|
||||
QList<QgsAbstractProcessingParameterWidgetWrapper *> wrappers;
|
||||
wrappers << &layerWrapper << &groupsWrapper << &timeWrapper;
|
||||
|
||||
QgsProject project;
|
||||
QgsProcessingContext context;
|
||||
context.setProject( &project );
|
||||
QgsProcessingParameterWidgetContext widgetContext;
|
||||
std::unique_ptr<QgsMapCanvas> mapCanvas = qgis::make_unique<QgsMapCanvas>();
|
||||
widgetContext.setMapCanvas( mapCanvas.get() );
|
||||
|
||||
widgetContext.setProject( &project );
|
||||
layerWrapper.setWidgetContext( widgetContext );
|
||||
groupsWrapper.setWidgetContext( widgetContext );
|
||||
timeWrapper.setWidgetContext( widgetContext );
|
||||
|
||||
TestProcessingContextGenerator generator( context );
|
||||
layerWrapper.registerProcessingContextGenerator( &generator );
|
||||
groupsWrapper.registerProcessingContextGenerator( &generator );
|
||||
timeWrapper.registerProcessingContextGenerator( &generator );
|
||||
|
||||
QSignalSpy layerSpy( &layerWrapper, &QgsProcessingMeshLayerWidgetWrapper::widgetValueHasChanged );
|
||||
QSignalSpy groupsSpy( &groupsWrapper, &QgsProcessingMeshDatasetGroupsWidgetWrapper::widgetValueHasChanged );
|
||||
QSignalSpy timeSpy( &timeWrapper, &QgsProcessingMeshDatasetTimeWidgetWrapper::widgetValueHasChanged );
|
||||
|
||||
std::unique_ptr<QWidget> layerWidget( layerWrapper.createWrappedWidget( context ) );
|
||||
std::unique_ptr<QWidget> groupWidget( groupsWrapper.createWrappedWidget( context ) );
|
||||
std::unique_ptr<QWidget> timeWidget( timeWrapper.createWrappedWidget( context ) );
|
||||
QgsProcessingMeshDatasetGroupsWidget *datasetGroupWidget = qobject_cast<QgsProcessingMeshDatasetGroupsWidget *>( groupWidget.get() );
|
||||
QgsProcessingMeshDatasetTimeWidget *datasetTimeWidget = qobject_cast<QgsProcessingMeshDatasetTimeWidget *>( timeWidget.get() );
|
||||
|
||||
QVERIFY( layerWidget );
|
||||
QVERIFY( groupWidget );
|
||||
QVERIFY( datasetGroupWidget );
|
||||
QVERIFY( timeWidget );
|
||||
|
||||
groupsWrapper.postInitialize( wrappers );
|
||||
timeWrapper.postInitialize( wrappers );
|
||||
|
||||
layerSpy.clear();
|
||||
groupsSpy.clear();
|
||||
timeSpy.clear();
|
||||
|
||||
QString dataDir = QString( TEST_DATA_DIR ); //defined in CmakeLists.txt
|
||||
QString meshOutOfProject( dataDir + "/mesh/trap_steady_05_3D.nc" );
|
||||
layerWrapper.setWidgetValue( meshOutOfProject, context );
|
||||
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 1 );
|
||||
QCOMPARE( timeSpy.count(), 1 );
|
||||
|
||||
QVariantList groups;
|
||||
groups << 0;
|
||||
groupsWrapper.setWidgetValue( groups, context );
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 2 );
|
||||
QCOMPARE( timeSpy.count(), 3 );
|
||||
QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsWrapper.widgetValue() ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsWrapper.widgetValue() ), QList<int>() << 0 );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "static" ) );
|
||||
QVERIFY( !datasetTimeWidget->isEnabled() );
|
||||
|
||||
groups << 11;
|
||||
groupsWrapper.setWidgetValue( groups, context );
|
||||
QCOMPARE( layerSpy.count(), 1 );
|
||||
QCOMPARE( groupsSpy.count(), 3 );
|
||||
QCOMPARE( timeSpy.count(), 5 );
|
||||
QVERIFY( datasetTimeWidget->isEnabled() );
|
||||
QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsWrapper.widgetValue() ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsWrapper.widgetValue() ), QList<int>() << 0 << 11 );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "dataset-time-step" ) );
|
||||
QVERIFY( QgsProcessingParameterMeshDatasetTime::timeValueAsDatasetIndex( timeWrapper.widgetValue() ) == QgsMeshDatasetIndex( 11, 0 ) );
|
||||
|
||||
QVERIFY( datasetTimeWidget->radioButtonDefinedDateTime->isEnabled() );
|
||||
QVERIFY( !datasetTimeWidget->radioButtonCurrentCanvasTime->isEnabled() );
|
||||
|
||||
datasetTimeWidget->radioButtonDefinedDateTime->setChecked( true );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "defined-date-time" ) );
|
||||
QCOMPARE( QgsProcessingParameterMeshDatasetTime::timeValueAsDefinedDateTime( timeWrapper.widgetValue() ),
|
||||
QDateTime( QDate( 1990, 1, 1 ), QTime( 0, 0, 0 ), Qt::UTC ) );
|
||||
|
||||
|
||||
mapCanvas->setTemporalRange( QgsDateTimeRange( QDateTime( QDate( 2021, 1, 1 ), QTime( 0, 3, 0 ), Qt::UTC ), QDateTime( QDate( 2020, 1, 1 ), QTime( 0, 5, 0 ), Qt::UTC ) ) );
|
||||
QVERIFY( datasetTimeWidget->radioButtonCurrentCanvasTime->isEnabled() );
|
||||
|
||||
}
|
||||
|
||||
void TestProcessingGui::testModelGraphicsView()
|
||||
{
|
||||
// test model
|
||||
|
Loading…
x
Reference in New Issue
Block a user