30 #include <QTextStream>
35 static QgsFields createFields(
const QList<QgsMeshDatasetGroupMetadata> &groupMetadataList,
int vectorOption )
40 if ( meta.isVector() )
42 if ( vectorOption == 0 || vectorOption == 2 )
44 fields.
append( QStringLiteral(
"%1_x" ).arg( meta.name() ) );
45 fields.
append( QStringLiteral(
"%1_y" ).arg( meta.name() ) );
48 if ( vectorOption == 1 || vectorOption == 2 )
50 fields.
append( QStringLiteral(
"%1_mag" ).arg( meta.name() ) );
51 fields.
append( QStringLiteral(
"%1_dir" ).arg( meta.name() ) );
55 fields.
append( meta.name() );
62 QVector<double> ret( exportOption == 2 ? 4 : 2 );
64 if ( exportOption == 0 || exportOption == 2 )
69 if ( exportOption == 1 || exportOption == 2 )
73 double magnitude = sqrt( x * x + y * y );
74 double direction = ( asin( x / magnitude ) ) / M_PI * 180;
76 direction = 180 - direction;
78 if ( exportOption == 1 )
83 if ( exportOption == 2 )
96 QVector<double> vectorValues = vectorValue( value, vectorOption );
97 for (
double v : vectorValues )
99 if ( v == std::numeric_limits<double>::quiet_NaN() )
100 attributes.append( QVariant() );
102 attributes.append( v );
107 if ( value.
scalar() == std::numeric_limits<double>::quiet_NaN() )
108 attributes.append( QVariant() );
110 attributes.append( value.
scalar() );
117 int triangularFaceIndex,
123 bool faceActive = activeFaces.
active( nativeFaceIndex );
135 value = datasetValues.
value( nativeFaceIndex );
142 const int v1 = face[0], v2 = face[1], v3 = face[2];
147 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
x(), val2.
x(), val3.
x(), point );
148 double y = std::numeric_limits<double>::quiet_NaN();
149 bool isVector = metadata.
isVector();
151 y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
y(), val2.
y(), val3.
y(), point );
162 QString QgsExportMeshOnElement::group()
const
164 return QObject::tr(
"Mesh" );
167 QString QgsExportMeshOnElement::groupId()
const
169 return QStringLiteral(
"mesh" );
172 QString QgsExportMeshVerticesAlgorithm::shortHelpString()
const
174 return QObject::tr(
"This algorithm exports a mesh layer's vertices to a point vector layer, with the dataset values on vertices as attribute values." );
177 QString QgsExportMeshVerticesAlgorithm::shortDescription()
const
179 return QObject::tr(
"Exports mesh vertices to a point vector layer" );
182 QString QgsExportMeshVerticesAlgorithm::name()
const
184 return QStringLiteral(
"exportmeshvertices" );
187 QString QgsExportMeshVerticesAlgorithm::displayName()
const
189 return QObject::tr(
"Export mesh vertices" );
194 return new QgsExportMeshVerticesAlgorithm();
197 QgsGeometry QgsExportMeshVerticesAlgorithm::meshElement(
int index )
const
202 void QgsExportMeshOnElement::initAlgorithm(
const QVariantMap &configuration )
204 Q_UNUSED( configuration );
210 QStringLiteral(
"DATASET_GROUPS" ),
211 QObject::tr(
"Dataset groups" ),
212 QStringLiteral(
"INPUT" ),
213 supportedDataType() ) );
216 QStringLiteral(
"DATASET_TIME" ),
217 QObject::tr(
"Dataset time" ),
218 QStringLiteral(
"INPUT" ),
219 QStringLiteral(
"DATASET_GROUPS" ) ) );
221 addParameter(
new QgsProcessingParameterCrs( QStringLiteral(
"CRS_OUTPUT" ), QObject::tr(
"Output coordinate system" ), QVariant(),
true ) );
223 QStringList exportVectorOptions;
224 exportVectorOptions << QObject::tr(
"Cartesian (x,y)" )
225 << QObject::tr(
"Polar (magnitude,degree)" )
226 << QObject::tr(
"Cartesian and Polar" );
227 addParameter(
new QgsProcessingParameterEnum( QStringLiteral(
"VECTOR_OPTION" ), QObject::tr(
"Export vector option" ), exportVectorOptions,
false, 0 ) );
237 if ( timeType == QLatin1String(
"dataset-time-step" ) )
242 else if ( timeType == QLatin1String(
"defined-date-time" ) )
245 if ( dateTime.isValid() )
246 relativeTime =
QgsInterval( layerReferenceTime.secsTo( dateTime ) );
248 else if ( timeType == QLatin1String(
"current-context-time" ) )
251 if ( dateTime.isValid() )
252 relativeTime =
QgsInterval( layerReferenceTime.secsTo( dateTime ) );
261 QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral(
"INPUT" ), context );
263 if ( !meshLayer || !meshLayer->
isValid() )
278 QList<int> datasetGroups =
287 QVariant parameterTimeVariant = parameters.value( QStringLiteral(
"DATASET_TIME" ) );
288 QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
290 switch ( meshElementType() )
293 mElementCount = mNativeMesh.faceCount();
296 mElementCount = mNativeMesh.vertexCount();
299 mElementCount = mNativeMesh.edgeCount();
303 for (
int i = 0; i < datasetGroups.count(); ++i )
305 int groupIndex = datasetGroups.at( i );
310 if ( supportedDataType().contains( dataGroup.metadata.dataType() ) )
312 dataGroup.datasetValues = meshLayer->
datasetValues( datasetIndex, 0, mElementCount );
313 mDataPerGroup.append( dataGroup );
316 feedback->
setProgress( 100 * i / datasetGroups.count() );
319 mExportVectorOption = parameterAsInt( parameters, QStringLiteral(
"VECTOR_OPTION" ), context );
329 return QVariantMap();
331 feedback->
setProgressText( QObject::tr(
"Creating output vector layer" ) );
334 QList<QgsMeshDatasetGroupMetadata> metaList;
335 metaList.reserve( mDataPerGroup.size() );
336 for (
const DataGroup &dataGroup : mDataPerGroup )
337 metaList.append( dataGroup.metadata );
338 QgsFields fields = createFields( metaList, mExportVectorOption );
343 QStringLiteral(
"OUTPUT" ),
350 return QVariantMap();
355 return QVariantMap();
357 feedback->
setProgressText( QObject::tr(
"Creating points for each vertices" ) );
360 for (
int i = 0; i < mElementCount; ++i )
363 for (
const DataGroup &dataGroup : std::as_const( mDataPerGroup ) )
366 addAttributes( value, attributes, dataGroup.metadata.isVector(), mExportVectorOption );
377 geom = meshElement( i );
379 feedback->
reportError( QObject::tr(
"Could not transform point to destination CRS" ) );
390 return QVariantMap();
396 ret[QStringLiteral(
"OUTPUT" )] = identifier;
401 QString QgsExportMeshFacesAlgorithm::shortHelpString()
const
403 return QObject::tr(
"This algorithm exports a mesh layer's faces to a polygon vector layer, with the dataset values on faces as attribute values." );
406 QString QgsExportMeshFacesAlgorithm::shortDescription()
const
408 return QObject::tr(
"Exports mesh faces to a polygon vector layer" );
411 QString QgsExportMeshFacesAlgorithm::name()
const
413 return QStringLiteral(
"exportmeshfaces" );
416 QString QgsExportMeshFacesAlgorithm::displayName()
const
418 return QObject::tr(
"Export mesh faces" );
423 return new QgsExportMeshFacesAlgorithm();
426 QgsGeometry QgsExportMeshFacesAlgorithm::meshElement(
int index )
const
428 const QgsMeshFace &face = mNativeMesh.face( index );
429 QVector<QgsPoint> vertices( face.size() );
430 for (
int i = 0; i < face.size(); ++i )
431 vertices[i] = mNativeMesh.vertex( face.at( i ) );
432 std::unique_ptr<QgsPolygon> polygon = std::make_unique<QgsPolygon>();
437 QString QgsExportMeshEdgesAlgorithm::shortHelpString()
const
439 return QObject::tr(
"This algorithm exports a mesh layer's edges to a line vector layer, with the dataset values on edges as attribute values." );
442 QString QgsExportMeshEdgesAlgorithm::shortDescription()
const
444 return QObject::tr(
"Exports mesh edges to a line vector layer" );
447 QString QgsExportMeshEdgesAlgorithm::name()
const
449 return QStringLiteral(
"exportmeshedges" );
452 QString QgsExportMeshEdgesAlgorithm::displayName()
const
454 return QObject::tr(
"Export mesh edges" );
459 return new QgsExportMeshEdgesAlgorithm();
462 QgsGeometry QgsExportMeshEdgesAlgorithm::meshElement(
int index )
const
464 const QgsMeshEdge &edge = mNativeMesh.edge( index );
465 QVector<QgsPoint> vertices( 2 );
466 vertices[0] = mNativeMesh.vertex( edge.first );
467 vertices[1] = mNativeMesh.vertex( edge.second );
472 QString QgsExportMeshOnGridAlgorithm::name()
const {
return QStringLiteral(
"exportmeshongrid" );}
474 QString QgsExportMeshOnGridAlgorithm::displayName()
const {
return QObject::tr(
"Export mesh on grid" );}
476 QString QgsExportMeshOnGridAlgorithm::group()
const {
return QObject::tr(
"Mesh" );}
478 QString QgsExportMeshOnGridAlgorithm::groupId()
const {
return QStringLiteral(
"mesh" );}
480 QString QgsExportMeshOnGridAlgorithm::shortHelpString()
const
482 return QObject::tr(
"This algorithm exports a mesh layer's dataset values to a gridded point vector layer, with the dataset values on each point as attribute values.\n"
483 "For data on volume (3D stacked dataset values), the exported dataset values are averaged on faces using the method defined in the mesh layer properties (default is Multi level averaging method).\n"
484 "1D meshes are not supported." );
487 QString QgsExportMeshOnGridAlgorithm::shortDescription()
const
489 return QObject::tr(
"Exports mesh dataset values to a gridded point vector layer" );
494 return new QgsExportMeshOnGridAlgorithm();
497 void QgsExportMeshOnGridAlgorithm::initAlgorithm(
const QVariantMap &configuration )
499 Q_UNUSED( configuration );
504 QStringLiteral(
"DATASET_GROUPS" ),
505 QObject::tr(
"Dataset groups" ),
506 QStringLiteral(
"INPUT" ),
507 supportedDataType() ) );
510 QStringLiteral(
"DATASET_TIME" ),
511 QObject::tr(
"Dataset time" ),
512 QStringLiteral(
"INPUT" ),
513 QStringLiteral(
"DATASET_GROUPS" ) ) );
517 addParameter(
new QgsProcessingParameterDistance( QStringLiteral(
"GRID_SPACING" ), QObject::tr(
"Grid spacing" ), 10, QStringLiteral(
"INPUT" ),
false ) );
519 addParameter(
new QgsProcessingParameterCrs( QStringLiteral(
"CRS_OUTPUT" ), QObject::tr(
"Output coordinate system" ), QVariant(),
true ) );
521 QStringList exportVectorOptions;
522 exportVectorOptions << QObject::tr(
"Cartesian (x,y)" )
523 << QObject::tr(
"Polar (magnitude,degree)" )
524 << QObject::tr(
"Cartesian and Polar" );
525 addParameter(
new QgsProcessingParameterEnum( QStringLiteral(
"VECTOR_OPTION" ), QObject::tr(
"Export vector option" ), exportVectorOptions,
false, 0 ) );
529 static void extractDatasetValues(
const QList<int> &datasetGroups,
533 const QSet<int> supportedDataType,
534 QList<DataGroup> &datasetPerGroup,
537 for (
int i = 0; i < datasetGroups.count(); ++i )
539 int groupIndex = datasetGroups.at( i );
544 if ( supportedDataType.contains( dataGroup.metadata.dataType() ) )
548 dataGroup.datasetValues = meshLayer->
datasetValues( datasetIndex, 0, valueCount );
552 dataGroup.dataset3dStakedValue = meshLayer->
dataset3dValues( datasetIndex, 0, valueCount );
554 datasetPerGroup.append( dataGroup );
557 feedback->
setProgress( 100 * i / datasetGroups.count() );
563 QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral(
"INPUT" ), context );
565 if ( !meshLayer || !meshLayer->
isValid() )
577 QList<int> datasetGroups =
586 QVariant parameterTimeVariant = parameters.value( QStringLiteral(
"DATASET_TIME" ) );
587 QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
589 extractDatasetValues( datasetGroups, meshLayer, nativeMesh, relativeTime, supportedDataType(), mDataPerGroup, feedback );
590 mTriangularMesh.update( meshLayer->
nativeMesh(), mTransform );
592 mExportVectorOption = parameterAsInt( parameters, QStringLiteral(
"VECTOR_OPTION" ), context );
602 return QVariantMap();
604 feedback->
setProgressText( QObject::tr(
"Creating output vector layer" ) );
609 for ( DataGroup &dataGroup : mDataPerGroup )
611 if ( dataGroup.dataset3dStakedValue.isValid() )
612 dataGroup.datasetValues = avgMethod->
calculate( dataGroup.dataset3dStakedValue );
615 QList<QgsMeshDatasetGroupMetadata> metaList;
616 metaList.reserve( mDataPerGroup.size() );
617 for (
const DataGroup &dataGroup : std::as_const( mDataPerGroup ) )
618 metaList.append( dataGroup.metadata );
619 QgsFields fields = createFields( metaList, mExportVectorOption );
625 QStringLiteral(
"OUTPUT" ),
632 return QVariantMap();
637 return QVariantMap();
643 double gridSpacing = parameterAsDouble( parameters, QStringLiteral(
"GRID_SPACING" ), context );
644 QgsRectangle extent = parameterAsExtent( parameters, QStringLiteral(
"EXTENT" ), context );
646 extent = mTriangularMesh.extent();
647 int pointXCount = int( extent.
width() / gridSpacing ) + 1;
648 int pointYCount = int( extent.
height() / gridSpacing ) + 1;
650 for (
int ix = 0; ix < pointXCount; ++ix )
652 for (
int iy = 0; iy < pointYCount; ++iy )
655 int triangularFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
656 if ( triangularFaceIndex >= 0 )
660 int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces().at( triangularFaceIndex );
661 for (
int i = 0; i < mDataPerGroup.count(); ++i )
663 const DataGroup &dataGroup = mDataPerGroup.at( i );
664 bool faceActive = dataGroup.activeFaces.active( nativeFaceIndex );
672 dataGroup.activeFaces,
673 dataGroup.datasetValues,
674 dataGroup.metadata );
676 if ( dataGroup.metadata.isVector() )
678 QVector<double> vector = vectorValue( dataGroup.datasetValues.value( i ), mExportVectorOption );
679 for (
double v : vector )
681 attributes.append( v );
685 attributes.append( value.
scalar() );
696 feedback->
reportError( QObject::tr(
"Could not transform point to destination CRS" ) );
707 ret[QStringLiteral(
"OUTPUT" )] = identifier;
712 QSet<int> QgsExportMeshOnGridAlgorithm::supportedDataType()
721 QString QgsMeshRasterizeAlgorithm::name()
const
723 return QStringLiteral(
"meshrasterize" );
726 QString QgsMeshRasterizeAlgorithm::displayName()
const
728 return QObject::tr(
"Rasterize mesh dataset" );
731 QString QgsMeshRasterizeAlgorithm::group()
const
733 return QObject::tr(
"Mesh" );
736 QString QgsMeshRasterizeAlgorithm::groupId()
const
738 return QStringLiteral(
"mesh" );
741 QString QgsMeshRasterizeAlgorithm::shortHelpString()
const
743 return QObject::tr(
"This algorithm creates a raster layer from a mesh dataset.\n"
744 "For data on volume (3D stacked dataset values), the exported dataset values are averaged on faces using the method defined in the mesh layer properties (default is Multi level averaging method).\n"
745 "1D meshes are not supported." );
748 QString QgsMeshRasterizeAlgorithm::shortDescription()
const
750 return QObject::tr(
"Creates a raster layer from a mesh dataset" );
755 return new QgsMeshRasterizeAlgorithm();
758 void QgsMeshRasterizeAlgorithm::initAlgorithm(
const QVariantMap &configuration )
760 Q_UNUSED( configuration );
765 QStringLiteral(
"DATASET_GROUPS" ),
766 QObject::tr(
"Dataset groups" ),
767 QStringLiteral(
"INPUT" ),
772 QStringLiteral(
"DATASET_TIME" ),
773 QObject::tr(
"Dataset time" ),
774 QStringLiteral(
"INPUT" ),
775 QStringLiteral(
"DATASET_GROUPS" ) ) );
779 addParameter(
new QgsProcessingParameterDistance( QStringLiteral(
"PIXEL_SIZE" ), QObject::tr(
"Pixel size" ), 1, QStringLiteral(
"INPUT" ),
false ) );
781 addParameter(
new QgsProcessingParameterCrs( QStringLiteral(
"CRS_OUTPUT" ), QObject::tr(
"Output coordinate system" ), QVariant(),
true ) );
788 QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral(
"INPUT" ), context );
790 if ( !meshLayer || !meshLayer->
isValid() )
800 mTriangularMesh.update( meshLayer->
nativeMesh(), mTransform );
802 QList<int> datasetGroups =
811 QVariant parameterTimeVariant = parameters.value( QStringLiteral(
"DATASET_TIME" ) );
812 QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
814 extractDatasetValues( datasetGroups, meshLayer, *meshLayer->
nativeMesh(), relativeTime, supportedDataType(), mDataPerGroup, feedback );
826 return QVariantMap();
833 for ( DataGroup &dataGroup : mDataPerGroup )
835 if ( dataGroup.dataset3dStakedValue.isValid() )
836 dataGroup.datasetValues = avgMethod->
calculate( dataGroup.dataset3dStakedValue );
840 double pixelSize = parameterAsDouble( parameters, QStringLiteral(
"PIXEL_SIZE" ), context );
841 QgsRectangle extent = parameterAsExtent( parameters, QStringLiteral(
"EXTENT" ), context );
843 extent = mTriangularMesh.extent();
845 int width = extent.
width() / pixelSize;
846 int height = extent.
height() / pixelSize;
848 QString fileName = parameterAsOutputLayer( parameters, QStringLiteral(
"OUTPUT" ), context );
849 QFileInfo fileInfo( fileName );
852 rasterFileWriter.setOutputProviderKey( QStringLiteral(
"gdal" ) );
853 rasterFileWriter.setOutputFormat( outputFormat );
855 std::unique_ptr<QgsRasterDataProvider> rasterDataProvider(
856 rasterFileWriter.createMultiBandRaster(
Qgis::DataType::Float64, width, height, extent, mTransform.destinationCrs(), mDataPerGroup.count() ) );
857 rasterDataProvider->setEditable(
true );
859 for (
int i = 0; i < mDataPerGroup.count(); ++i )
861 const DataGroup &dataGroup = mDataPerGroup.at( i );
866 if ( dataGroup.datasetValues.isValid() )
870 dataGroup.datasetValues,
871 dataGroup.activeFaces,
872 dataGroup.metadata.dataType(),
876 &rasterBlockFeedBack ) );
878 rasterDataProvider->writeBlock( block.get(), i + 1 );
879 rasterDataProvider->setNoDataValue( i + 1, block->noDataValue() );
882 rasterDataProvider->setNoDataValue( i + 1, std::numeric_limits<double>::quiet_NaN() );
887 return QVariantMap();
888 feedback->
setProgress( 100 * i / mDataPerGroup.count() );
892 rasterDataProvider->setEditable(
false );
898 ret[QStringLiteral(
"OUTPUT" )] = fileName;
903 QSet<int> QgsMeshRasterizeAlgorithm::supportedDataType()
912 QString QgsMeshContoursAlgorithm::name()
const
914 return QStringLiteral(
"meshcontours" );
917 QString QgsMeshContoursAlgorithm::displayName()
const
919 return QObject::tr(
"Export contours" );
922 QString QgsMeshContoursAlgorithm::group()
const
924 return QObject::tr(
"Mesh" );
927 QString QgsMeshContoursAlgorithm::groupId()
const
929 return QStringLiteral(
"mesh" );
932 QString QgsMeshContoursAlgorithm::shortHelpString()
const
934 return QObject::tr(
"This algorithm creates contours as a vector layer from a mesh scalar dataset." );
937 QString QgsMeshContoursAlgorithm::shortDescription()
const
939 return QObject::tr(
"Creates contours as vector layer from mesh scalar dataset" );
944 return new QgsMeshContoursAlgorithm();
947 void QgsMeshContoursAlgorithm::initAlgorithm(
const QVariantMap &configuration )
949 Q_UNUSED( configuration );
954 QStringLiteral(
"DATASET_GROUPS" ),
955 QObject::tr(
"Dataset groups" ),
956 QStringLiteral(
"INPUT" ),
957 supportedDataType() ) );
960 QStringLiteral(
"DATASET_TIME" ),
961 QObject::tr(
"Dataset time" ),
962 QStringLiteral(
"INPUT" ),
963 QStringLiteral(
"DATASET_GROUPS" ) ) );
973 std::unique_ptr< QgsProcessingParameterString > contourLevelList = std::make_unique < QgsProcessingParameterString >(
974 QStringLiteral(
"CONTOUR_LEVEL_LIST" ), QObject::tr(
"List of contours level" ), QVariant(),
false,
true );
975 contourLevelList->setHelp( QObject::tr(
"Comma separated list of values to export. If filled, the increment, minimum and maximum settings are ignored." ) );
976 addParameter( contourLevelList.release() );
978 addParameter(
new QgsProcessingParameterCrs( QStringLiteral(
"CRS_OUTPUT" ), QObject::tr(
"Output coordinate system" ), QVariant(),
true ) );
987 QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral(
"INPUT" ), context );
989 if ( !meshLayer || !meshLayer->
isValid() )
999 mTriangularMesh.update( meshLayer->
nativeMesh(), mTransform );
1005 QString levelsString = parameterAsString( parameters, QStringLiteral(
"CONTOUR_LEVEL_LIST" ), context );
1006 if ( ! levelsString.isEmpty() )
1008 QStringList levelStringList = levelsString.split(
',' );
1009 if ( !levelStringList.isEmpty() )
1011 for (
const QString &stringVal : levelStringList )
1014 double val = stringVal.toDouble( &ok );
1016 mLevels.append( val );
1018 throw QgsProcessingException( QObject::tr(
"Invalid format for level values, must be numbers separated with comma" ) );
1020 if ( mLevels.count() >= 2 )
1021 if ( mLevels.last() <= mLevels.at( mLevels.count() - 2 ) )
1022 throw QgsProcessingException( QObject::tr(
"Invalid format for level values, must be different numbers and in increasing order" ) );
1027 if ( mLevels.isEmpty() )
1029 double minimum = parameterAsDouble( parameters, QStringLiteral(
"MINIMUM" ), context );
1030 double maximum = parameterAsDouble( parameters, QStringLiteral(
"MAXIMUM" ), context );
1031 double interval = parameterAsDouble( parameters, QStringLiteral(
"INCREMENT" ), context );
1033 if ( interval <= 0 )
1036 if ( minimum >= maximum )
1037 throw QgsProcessingException( QObject::tr(
"Invalid minimum and maximum values, minimum must be lesser than maximum" ) );
1039 if ( interval > ( maximum - minimum ) )
1040 throw QgsProcessingException( QObject::tr(
"Invalid minimum, maximum and interval values, difference between minimum and maximum must be greater or equal than interval" ) );
1042 int intervalCount = ( maximum - minimum ) / interval;
1044 mLevels.reserve( intervalCount );
1045 for (
int i = 0; i < intervalCount; ++i )
1047 mLevels.append( minimum + i * interval );
1052 QList<int> datasetGroups =
1061 QVariant parameterTimeVariant = parameters.value( QStringLiteral(
"DATASET_TIME" ) );
1062 QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
1066 extractDatasetValues( datasetGroups, meshLayer, mNativeMesh, relativeTime, supportedDataType(), mDataPerGroup, feedback );
1077 for ( DataGroup &dataGroup : mDataPerGroup )
1079 if ( dataGroup.dataset3dStakedValue.isValid() )
1080 dataGroup.datasetValues = avgMethod->
calculate( dataGroup.dataset3dStakedValue );
1086 polygonFields.
append( QObject::tr(
"group" ) );
1087 polygonFields.
append( QObject::tr(
"time" ) );
1088 polygonFields.
append( QObject::tr(
"min_value" ) );
1089 polygonFields.
append( QObject::tr(
"max_value" ) );
1090 lineFields.
append( QObject::tr(
"group" ) );
1091 lineFields.
append( QObject::tr(
"time" ) );
1092 lineFields.
append( QObject::tr(
"value" ) );
1096 QString lineIdentifier;
1097 QString polygonIdentifier;
1099 QStringLiteral(
"OUTPUT_POLYGONS" ),
1106 QStringLiteral(
"OUTPUT_LINES" ),
1113 if ( !sinkLines || !sinkPolygons )
1114 return QVariantMap();
1117 for (
int i = 0; i < mDataPerGroup.count(); ++i )
1119 DataGroup dataGroup = mDataPerGroup.at( i );
1121 int count = scalarDataOnVertices ? mNativeMesh.vertices.count() : mNativeMesh.faces.count();
1123 QVector<double> values;
1124 if ( dataGroup.datasetValues.isValid() )
1127 values = QgsMeshLayerUtils::calculateMagnitudes( dataGroup.datasetValues );
1131 values = QVector<double>( count, std::numeric_limits<double>::quiet_NaN() );
1134 if ( ( !scalarDataOnVertices ) )
1136 values = QgsMeshLayerUtils::interpolateFromFacesData(
1139 &dataGroup.activeFaces,
1144 QgsMeshContours contoursExported( mTriangularMesh, mNativeMesh, values, dataGroup.activeFaces );
1147 firstAttributes.append( dataGroup.metadata.name() );
1148 firstAttributes.append( mDateTimeString );
1150 for (
double level : std::as_const( mLevels ) )
1152 QgsGeometry line = contoursExported.exportLines( level, feedback );
1154 return QVariantMap();
1158 lineAttributes.append( level );
1168 for (
int l = 0; l < mLevels.count() - 1; ++l )
1170 QgsGeometry polygon = contoursExported.exportPolygons( mLevels.at( l ), mLevels.at( l + 1 ), feedback );
1172 return QVariantMap();
1177 polygonAttributes.append( mLevels.at( l ) );
1178 polygonAttributes.append( mLevels.at( l + 1 ) );
1188 feedback->
setProgress( 100 * i / mDataPerGroup.count() );
1193 ret[QStringLiteral(
"OUTPUT_LINES" )] = lineIdentifier;
1194 ret[QStringLiteral(
"OUTPUT_POLYGONS" )] = polygonIdentifier;
1199 QString QgsMeshExportCrossSection::name()
const
1201 return QStringLiteral(
"meshexportcrosssection" );
1204 QString QgsMeshExportCrossSection::displayName()
const
1206 return QObject::tr(
"Export cross section dataset values on lines from mesh" );
1209 QString QgsMeshExportCrossSection::group()
const
1211 return QObject::tr(
"Mesh" );
1214 QString QgsMeshExportCrossSection::groupId()
const
1216 return QStringLiteral(
"mesh" );
1219 QString QgsMeshExportCrossSection::shortHelpString()
const
1221 return QObject::tr(
"This algorithm extracts mesh's dataset values from line contained in a vector layer.\n"
1222 "Each line is discretized with a resolution distance parameter for extraction of values on its vertices." );
1225 QString QgsMeshExportCrossSection::shortDescription()
const
1227 return QObject::tr(
"Extracts a mesh dataset's values from lines contained in a vector layer" );
1232 return new QgsMeshExportCrossSection();
1235 void QgsMeshExportCrossSection::initAlgorithm(
const QVariantMap &configuration )
1237 Q_UNUSED( configuration );
1242 QStringLiteral(
"DATASET_GROUPS" ),
1243 QObject::tr(
"Dataset groups" ),
1244 QStringLiteral(
"INPUT" ),
1245 supportedDataType() ) );
1248 QStringLiteral(
"DATASET_TIME" ),
1249 QObject::tr(
"Dataset time" ),
1250 QStringLiteral(
"INPUT" ),
1251 QStringLiteral(
"DATASET_GROUPS" ) ) );
1253 QList<int> datatype;
1256 QStringLiteral(
"INPUT_LINES" ), QObject::tr(
"Lines for data export" ), datatype, QVariant(),
false ) );
1259 QStringLiteral(
"RESOLUTION" ), QObject::tr(
"Line segmentation resolution" ), 10.0, QStringLiteral(
"INPUT_LINES" ),
false, 0 ) );
1268 QStringLiteral(
"OUTPUT" ), QObject::tr(
"Exported data CSV file" ), QObject::tr(
"CSV file (*.csv)" ) ) );
1273 QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral(
"INPUT" ), context );
1275 if ( !meshLayer || !meshLayer->
isValid() )
1278 mMeshLayerCrs = meshLayer->
crs();
1279 mTriangularMesh.update( meshLayer->
nativeMesh() );
1280 QList<int> datasetGroups =
1289 QVariant parameterTimeVariant = parameters.value( QStringLiteral(
"DATASET_TIME" ) );
1290 QgsInterval relativeTime = datasetRelativetime( parameterTimeVariant, meshLayer, context );
1292 extractDatasetValues( datasetGroups, meshLayer, *meshLayer->
nativeMesh(), relativeTime, supportedDataType(), mDataPerGroup, feedback );
1305 for ( DataGroup &dataGroup : mDataPerGroup )
1307 if ( dataGroup.dataset3dStakedValue.isValid() )
1308 dataGroup.datasetValues = avgMethod->
calculate( dataGroup.dataset3dStakedValue );
1310 double resolution = parameterAsDouble( parameters, QStringLiteral(
"RESOLUTION" ), context );
1311 int datasetDigits = parameterAsInt( parameters, QStringLiteral(
"DATASET_DIGITS" ), context );
1312 int coordDigits = parameterAsInt( parameters, QStringLiteral(
"COORDINATES_DIGITS" ), context );
1315 if ( !featureSource )
1320 QString outputFileName = parameterAsFileOutput( parameters, QStringLiteral(
"OUTPUT" ), context );
1321 QFile file( outputFileName );
1322 if ( ! file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
1325 QTextStream textStream( &file );
1326 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1327 textStream.setCodec(
"UTF-8" );
1330 header << QStringLiteral(
"fid" ) << QStringLiteral(
"x" ) << QStringLiteral(
"y" ) << QObject::tr(
"offset" );
1331 for (
const DataGroup &datagroup : std::as_const( mDataPerGroup ) )
1332 header << datagroup.metadata.name();
1333 textStream << header.join(
',' ) << QStringLiteral(
"\n" );
1336 long long featCounter = 0;
1350 feedback->
reportError( QObject::tr(
"Could not transform line to mesh CRS" ) );
1356 while ( offset <= line.
length() )
1359 return QVariantMap();
1361 QStringList textLine;
1363 int triangularFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
1364 textLine << QString::number( fid ) << QString::number( point.
x(),
'f', coordDigits ) << QString::number( point.
y(),
'f', coordDigits ) << QString::number( offset,
'f', coordDigits );
1365 if ( triangularFaceIndex >= 0 )
1369 int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces().at( triangularFaceIndex );
1370 for (
int i = 0; i < mDataPerGroup.count(); ++i )
1372 const DataGroup &dataGroup = mDataPerGroup.at( i );
1373 bool faceActive = dataGroup.activeFaces.active( nativeFaceIndex );
1379 triangularFaceIndex,
1381 dataGroup.activeFaces,
1382 dataGroup.datasetValues,
1383 dataGroup.metadata );
1385 if ( abs( value.
x() ) == std::numeric_limits<double>::quiet_NaN() )
1386 textLine << QString(
' ' );
1388 textLine << QString::number( value.
scalar(),
'f', datasetDigits );
1392 for (
int i = 0; i < mDataPerGroup.count(); ++i )
1393 textLine << QString(
' ' );
1395 textStream << textLine.join(
',' ) << QStringLiteral(
"\n" );
1397 offset += resolution;
1402 feedback->
setProgress( 100.0 * featCounter / featCount );
1404 return QVariantMap();
1411 ret[QStringLiteral(
"OUTPUT" )] = outputFileName;
1415 QString QgsMeshExportTimeSeries::name()
const
1417 return QStringLiteral(
"meshexporttimeseries" );
1420 QString QgsMeshExportTimeSeries::displayName()
const
1422 return QObject::tr(
"Export time series values from points of a mesh dataset" );
1425 QString QgsMeshExportTimeSeries::group()
const
1427 return QObject::tr(
"Mesh" );
1430 QString QgsMeshExportTimeSeries::groupId()
const
1432 return QStringLiteral(
"mesh" );
1435 QString QgsMeshExportTimeSeries::shortHelpString()
const
1437 return QObject::tr(
"This algorithm extracts mesh's dataset time series values from points contained in a vector layer.\n"
1438 "If the time step is kept to its default value (0 hours), the time step used is the one of the two first datasets of the first selected dataset group." );
1441 QString QgsMeshExportTimeSeries::shortDescription()
const
1443 return QObject::tr(
"Extracts a mesh dataset's time series values from points contained in a vector layer" );
1448 return new QgsMeshExportTimeSeries();
1451 void QgsMeshExportTimeSeries::initAlgorithm(
const QVariantMap &configuration )
1453 Q_UNUSED( configuration );
1458 QStringLiteral(
"DATASET_GROUPS" ),
1459 QObject::tr(
"Dataset groups" ),
1460 QStringLiteral(
"INPUT" ),
1461 supportedDataType() ) );
1464 QStringLiteral(
"STARTING_TIME" ),
1465 QObject::tr(
"Starting time" ),
1466 QStringLiteral(
"INPUT" ),
1467 QStringLiteral(
"DATASET_GROUPS" ) ) );
1470 QStringLiteral(
"FINISHING_TIME" ),
1471 QObject::tr(
"Finishing time" ),
1472 QStringLiteral(
"INPUT" ),
1473 QStringLiteral(
"DATASET_GROUPS" ) ) );
1478 QList<int> datatype;
1481 QStringLiteral(
"INPUT_POINTS" ), QObject::tr(
"Points for data export" ), datatype, QVariant(),
false ) );
1490 QStringLiteral(
"OUTPUT" ), QObject::tr(
"Exported data CSV file" ), QObject::tr(
"CSV file (*.csv)" ) ) );
1495 QgsMeshLayer *meshLayer = parameterAsMeshLayer( parameters, QStringLiteral(
"INPUT" ), context );
1497 if ( !meshLayer || !meshLayer->
isValid() )
1500 mMeshLayerCrs = meshLayer->
crs();
1501 mTriangularMesh.update( meshLayer->
nativeMesh() );
1503 QList<int> datasetGroups =
1512 QVariant parameterStartTimeVariant = parameters.value( QStringLiteral(
"STARTING_TIME" ) );
1513 QgsInterval relativeStartTime = datasetRelativetime( parameterStartTimeVariant, meshLayer, context );
1515 QVariant parameterEndTimeVariant = parameters.value( QStringLiteral(
"FINISHING_TIME" ) );
1516 QgsInterval relativeEndTime = datasetRelativetime( parameterEndTimeVariant, meshLayer, context );
1519 qint64 timeStepInterval = parameterAsDouble( parameters, QStringLiteral(
"TIME_STEP" ), context ) * 1000 * 3600;
1520 if ( timeStepInterval == 0 )
1523 for (
int groupIndex : datasetGroups )
1537 mRelativeTimeSteps.clear();
1538 mTimeStepString.clear();
1539 if ( timeStepInterval != 0 )
1541 mRelativeTimeSteps.append( relativeStartTime.
seconds() * 1000 );
1542 while ( mRelativeTimeSteps.last() < relativeEndTime.
seconds() * 1000 )
1543 mRelativeTimeSteps.append( mRelativeTimeSteps.last() + timeStepInterval );
1545 for ( qint64 relativeTimeStep : std::as_const( mRelativeTimeSteps ) )
1547 mTimeStepString.append( meshLayer->
formatTime( relativeTimeStep / 3600.0 / 1000.0 ) );
1552 for (
int i = 0; i < datasetGroups.count(); ++i )
1554 int groupIndex = datasetGroups.at( i );
1556 if ( supportedDataType().contains( meta.
dataType() ) )
1558 mGroupIndexes.append( groupIndex );
1559 mGroupsMetadata[groupIndex] = meta;
1563 if ( !mRelativeTimeSteps.isEmpty() )
1567 for ( qint64 relativeTimeStep : mRelativeTimeSteps )
1569 QMap<int, int> &groupIndexToData = mRelativeTimeToData[relativeTimeStep];
1570 QgsInterval timeStepInterval( relativeTimeStep / 1000.0 );
1572 if ( !datasetIndex.
isValid() )
1574 if ( datasetIndex != lastDatasetIndex )
1576 DataGroup dataGroup;
1577 dataGroup.metadata = meta;
1578 dataGroup.datasetValues = meshLayer->
datasetValues( datasetIndex, 0, valueCount );
1582 dataGroup.dataset3dStakedValue = meshLayer->
dataset3dValues( datasetIndex, 0, valueCount );
1584 mDatasets.append( dataGroup );
1585 lastDatasetIndex = datasetIndex;
1587 groupIndexToData[groupIndex] = mDatasets.count() - 1;
1593 QMap<int, int> &groupIndexToData = mRelativeTimeToData[0];
1595 DataGroup dataGroup;
1596 dataGroup.metadata = meta;
1597 dataGroup.datasetValues = meshLayer->
datasetValues( datasetIndex, 0, valueCount );
1601 dataGroup.dataset3dStakedValue = meshLayer->
dataset3dValues( datasetIndex, 0, valueCount );
1603 mDatasets.append( dataGroup );
1604 groupIndexToData[groupIndex] = mDatasets.
count() - 1;
1609 feedback->
setProgress( 100 * i / datasetGroups.count() );
1625 for ( DataGroup &dataGroup : mDatasets )
1627 if ( dataGroup.dataset3dStakedValue.isValid() )
1628 dataGroup.datasetValues = avgMethod->
calculate( dataGroup.dataset3dStakedValue );
1631 int datasetDigits = parameterAsInt( parameters, QStringLiteral(
"DATASET_DIGITS" ), context );
1632 int coordDigits = parameterAsInt( parameters, QStringLiteral(
"COORDINATES_DIGITS" ), context );
1635 if ( !featureSource )
1640 QString outputFileName = parameterAsFileOutput( parameters, QStringLiteral(
"OUTPUT" ), context );
1641 QFile file( outputFileName );
1642 if ( ! file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
1645 QTextStream textStream( &file );
1646 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1647 textStream.setCodec(
"UTF-8" );
1650 header << QStringLiteral(
"fid" ) << QStringLiteral(
"x" ) << QStringLiteral(
"y" ) << QObject::tr(
"time" );
1652 for (
int gi : std::as_const( mGroupIndexes ) )
1653 header << mGroupsMetadata.value( gi ).name();
1655 textStream << header.join(
',' ) << QStringLiteral(
"\n" );
1658 long long featCounter = 0;
1672 feedback->
reportError( QObject::tr(
"Could not transform line to mesh CRS" ) );
1679 int triangularFaceIndex = mTriangularMesh.faceIndexForPoint_v2( point );
1681 if ( triangularFaceIndex >= 0 )
1683 int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces().at( triangularFaceIndex );
1684 if ( !mRelativeTimeSteps.isEmpty() )
1686 for (
int timeIndex = 0; timeIndex < mRelativeTimeSteps.count(); ++timeIndex )
1688 qint64 timeStep = mRelativeTimeSteps.at( timeIndex );
1689 QStringList textLine;
1690 textLine << QString::number( fid )
1691 << QString::number( point.
x(),
'f', coordDigits )
1692 << QString::number( point.
y(),
'f', coordDigits )
1693 << mTimeStepString.at( timeIndex );
1695 if ( mRelativeTimeToData.contains( timeStep ) )
1697 const QMap<int, int> &groupToData = mRelativeTimeToData.value( timeStep );
1698 for (
int groupIndex : std::as_const( mGroupIndexes ) )
1700 if ( !groupToData.contains( groupIndex ) )
1702 int dataIndex = groupToData.value( groupIndex );
1703 if ( dataIndex < 0 || dataIndex > mDatasets.count() - 1 )
1706 const DataGroup &dataGroup = mDatasets.at( dataIndex );
1709 triangularFaceIndex,
1711 dataGroup.activeFaces,
1712 dataGroup.datasetValues,
1713 dataGroup.metadata );
1714 if ( abs( value.
x() ) == std::numeric_limits<double>::quiet_NaN() )
1715 textLine << QString(
' ' );
1717 textLine << QString::number( value.
scalar(),
'f', datasetDigits ) ;
1720 textStream << textLine.join(
',' ) << QStringLiteral(
"\n" );
1725 QStringList textLine;
1726 textLine << QString::number( fid )
1727 << QString::number( point.
x(),
'f', coordDigits )
1728 << QString::number( point.
y(),
'f', coordDigits )
1729 << QObject::tr(
"static dataset" );
1730 const QMap<int, int> &groupToData = mRelativeTimeToData.value( 0 );
1731 for (
int groupIndex : std::as_const( mGroupIndexes ) )
1733 if ( !groupToData.contains( groupIndex ) )
1735 int dataIndex = groupToData.value( groupIndex );
1736 if ( dataIndex < 0 || dataIndex > mDatasets.count() - 1 )
1738 const DataGroup &dataGroup = mDatasets.at( dataIndex );
1741 triangularFaceIndex,
1743 dataGroup.activeFaces,
1744 dataGroup.datasetValues,
1745 dataGroup.metadata );
1746 if ( abs( value.
x() ) == std::numeric_limits<double>::quiet_NaN() )
1747 textLine << QString(
' ' );
1749 textLine << QString::number( value.
scalar(),
'f', datasetDigits );
1751 textStream << textLine.join(
',' ) << QStringLiteral(
"\n" );
1757 feedback->
setProgress( 100.0 * featCounter / featCount );
1759 return QVariantMap();
1766 ret[QStringLiteral(
"OUTPUT" )] = outputFileName;