From a6b34e57908e6ead37f80adbc635bcafa7babd9d Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 28 Jan 2025 09:09:26 +1000 Subject: [PATCH 01/81] Rollback use of enum keys from 057402 for older settings This causes unnecessary project breakage, the settings are reset to default on reading older projects. We should only use enum key storage for new settings in order to avoid this. --- src/core/pointcloud/qgspointcloudrenderer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/pointcloud/qgspointcloudrenderer.cpp b/src/core/pointcloud/qgspointcloudrenderer.cpp index 1ef20cf09d001..144d233456cea 100644 --- a/src/core/pointcloud/qgspointcloudrenderer.cpp +++ b/src/core/pointcloud/qgspointcloudrenderer.cpp @@ -230,8 +230,8 @@ void QgsPointCloudRenderer::restoreCommonProperties( const QDomElement &element, mMaximumScreenError = element.attribute( QStringLiteral( "maximumScreenError" ), QStringLiteral( "0.3" ) ).toDouble(); mMaximumScreenErrorUnit = QgsUnitTypes::decodeRenderUnit( element.attribute( QStringLiteral( "maximumScreenErrorUnit" ), QStringLiteral( "MM" ) ) ); - mPointSymbol = qgsEnumKeyToValue( element.attribute( QStringLiteral( "pointSymbol" ) ), Qgis::PointCloudSymbol::Square ); - mDrawOrder2d = qgsEnumKeyToValue( element.attribute( QStringLiteral( "drawOrder2d" ) ), Qgis::PointCloudDrawOrder::Default ); + mPointSymbol = static_cast< Qgis::PointCloudSymbol >( element.attribute( QStringLiteral( "pointSymbol" ), QStringLiteral( "0" ) ).toInt() ); + mDrawOrder2d = static_cast< Qgis::PointCloudDrawOrder >( element.attribute( QStringLiteral( "drawOrder2d" ), QStringLiteral( "0" ) ).toInt() ); mRenderAsTriangles = element.attribute( QStringLiteral( "renderAsTriangles" ), QStringLiteral( "0" ) ).toInt(); mHorizontalTriangleFilter = element.attribute( QStringLiteral( "horizontalTriangleFilter" ), QStringLiteral( "0" ) ).toInt(); @@ -255,8 +255,8 @@ void QgsPointCloudRenderer::saveCommonProperties( QDomElement &element, const Qg element.setAttribute( QStringLiteral( "maximumScreenError" ), qgsDoubleToString( mMaximumScreenError ) ); element.setAttribute( QStringLiteral( "maximumScreenErrorUnit" ), QgsUnitTypes::encodeUnit( mMaximumScreenErrorUnit ) ); - element.setAttribute( QStringLiteral( "pointSymbol" ), qgsEnumValueToKey( mPointSymbol ) ); - element.setAttribute( QStringLiteral( "drawOrder2d" ), qgsEnumValueToKey( mDrawOrder2d ) ); + element.setAttribute( QStringLiteral( "pointSymbol" ), QString::number( static_cast< int >( mPointSymbol ) ) ); + element.setAttribute( QStringLiteral( "drawOrder2d" ), QString::number( static_cast< int >( mDrawOrder2d ) ) ); element.setAttribute( QStringLiteral( "renderAsTriangles" ), QString::number( static_cast< int >( mRenderAsTriangles ) ) ); element.setAttribute( QStringLiteral( "horizontalTriangleFilter" ), QString::number( static_cast< int >( mHorizontalTriangleFilter ) ) ); From 84e24f63d82c67cd9c9ddf81601490501f991e68 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 28 Jan 2025 09:13:57 +1000 Subject: [PATCH 02/81] Don't set zoomOutBehavior xml element if it is the default Avoid unnecessary project XML bloat --- src/core/pointcloud/qgspointcloudrenderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/pointcloud/qgspointcloudrenderer.cpp b/src/core/pointcloud/qgspointcloudrenderer.cpp index 144d233456cea..ff9ad0720d49e 100644 --- a/src/core/pointcloud/qgspointcloudrenderer.cpp +++ b/src/core/pointcloud/qgspointcloudrenderer.cpp @@ -270,7 +270,8 @@ void QgsPointCloudRenderer::saveCommonProperties( QDomElement &element, const Qg QDomDocument doc = element.ownerDocument(); element.appendChild( mLabelTextFormat.writeXml( doc, context ) ); } - element.setAttribute( QStringLiteral( "zoomOutBehavior" ), qgsEnumValueToKey( mZoomOutBehavior ) ); + if ( mZoomOutBehavior != Qgis::PointCloudZoomOutRenderBehavior::RenderExtents ) + element.setAttribute( QStringLiteral( "zoomOutBehavior" ), qgsEnumValueToKey( mZoomOutBehavior ) ); } Qgis::PointCloudSymbol QgsPointCloudRenderer::pointSymbol() const From 3e4951a9ae163c68a139d38124f30d7754477892 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Tue, 28 Jan 2025 18:56:03 +0000 Subject: [PATCH 03/81] allow editing and deleting vector join when child join item is selected (fix #29709) --- src/gui/vector/qgsvectorlayerproperties.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/gui/vector/qgsvectorlayerproperties.cpp b/src/gui/vector/qgsvectorlayerproperties.cpp index 7c90256e2898f..03d443228cca7 100644 --- a/src/gui/vector/qgsvectorlayerproperties.cpp +++ b/src/gui/vector/qgsvectorlayerproperties.cpp @@ -1305,8 +1305,16 @@ void QgsVectorLayerProperties::mJoinTreeWidget_itemDoubleClicked( QTreeWidgetIte return; } + // if current item is a child item, we should use its parent to be able to edit join + QTreeWidgetItem *currentJoinItem = item; + if ( item->parent() ) + { + currentJoinItem = item->parent(); + } + + QList joinedLayers; - QString joinLayerId = item->data( 0, Qt::UserRole ).toString(); + QString joinLayerId = currentJoinItem->data( 0, Qt::UserRole ).toString(); const QList &joins = mLayer->vectorJoins(); int j = -1; for ( int i = 0; i < joins.size(); ++i ) @@ -1478,6 +1486,12 @@ void QgsVectorLayerProperties::openPanel( QgsPanelWidget *panel ) void QgsVectorLayerProperties::mButtonRemoveJoin_clicked() { QTreeWidgetItem *currentJoinItem = mJoinTreeWidget->currentItem(); + // if current item is a child item, we should use its parent to be able to remove join + if ( currentJoinItem && currentJoinItem->parent() ) + { + currentJoinItem = mJoinTreeWidget->currentItem()->parent(); + } + if ( !mLayer || !currentJoinItem ) { return; From abe2cf8f6bd89c9d761e16877ea7800a4053003e Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Wed, 29 Jan 2025 09:36:43 +0000 Subject: [PATCH 04/81] better wording for an input parameter in Execute SpatiaLite query algorithm (refs ##53904) --- .../processing/qgsalgorithmexecutespatialitequery.cpp | 4 ++-- .../qgsalgorithmexecutespatialitequeryregistered.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp b/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp index 3611de8fb8092..d4dcb2f252b2d 100644 --- a/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp +++ b/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsalgorithmexecutepostgisquery.cpp + qgsalgorithmexecutespatialitequery.cpp --------------------- begin : May 2020 copyright : (C) 2020 by Alexander Bruy @@ -60,7 +60,7 @@ QgsExecuteSpatialiteQueryAlgorithm *QgsExecuteSpatialiteQueryAlgorithm::createIn void QgsExecuteSpatialiteQueryAlgorithm::initAlgorithm( const QVariantMap & ) { - addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "DATABASE" ), QObject::tr( "Database (connection name)" ), QList() << static_cast( Qgis::ProcessingSourceType::Vector ) ) ); + addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "DATABASE" ), QObject::tr( "Database layer (or file)" ), QList() << static_cast( Qgis::ProcessingSourceType::Vector ) ) ); addParameter( new QgsProcessingParameterString( QStringLiteral( "SQL" ), QObject::tr( "SQL query" ), QVariant(), true ) ); } diff --git a/src/analysis/processing/qgsalgorithmexecutespatialitequeryregistered.cpp b/src/analysis/processing/qgsalgorithmexecutespatialitequeryregistered.cpp index 56312cf53f5e0..b4b3f0fe520af 100644 --- a/src/analysis/processing/qgsalgorithmexecutespatialitequeryregistered.cpp +++ b/src/analysis/processing/qgsalgorithmexecutespatialitequeryregistered.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgsalgorithmexecutepostgisqueryregistered.cpp + qgsalgorithmexecutespatialitequeryregistered.cpp --------------------- begin : May 2020 copyright : (C) 2020 by Alexander Bruy From 4ff875ef045495ad13b839f162057ddcbc232dc5 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Wed, 29 Jan 2025 09:39:02 +0000 Subject: [PATCH 05/81] improve algorithm help --- src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp b/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp index d4dcb2f252b2d..3a9ab925aef28 100644 --- a/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp +++ b/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp @@ -50,7 +50,7 @@ QString QgsExecuteSpatialiteQueryAlgorithm::groupId() const QString QgsExecuteSpatialiteQueryAlgorithm::shortHelpString() const { - return QObject::tr( "Executes a SQL command on a SpatiaLite database." ); + return QObject::tr( "Executes a SQL command on a SpatiaLite database. The database is determined by an input layer or file." ); } QgsExecuteSpatialiteQueryAlgorithm *QgsExecuteSpatialiteQueryAlgorithm::createInstance() const From 6747035857652e39003b444f529f9a07299b2599 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Wed, 29 Jan 2025 09:56:46 +0000 Subject: [PATCH 06/81] remove debug --- src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp b/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp index 3a9ab925aef28..18fba8c3f92c9 100644 --- a/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp +++ b/src/analysis/processing/qgsalgorithmexecutespatialitequery.cpp @@ -66,7 +66,7 @@ void QgsExecuteSpatialiteQueryAlgorithm::initAlgorithm( const QVariantMap & ) QVariantMap QgsExecuteSpatialiteQueryAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) { - //Q_UNUSED( feedback ); + Q_UNUSED( feedback ); QgsVectorLayer *layer = parameterAsVectorLayer( parameters, QStringLiteral( "DATABASE" ), context ); QString databaseUri = layer->dataProvider()->dataSourceUri(); QgsDataSourceUri uri( databaseUri ); @@ -80,7 +80,6 @@ QVariantMap QgsExecuteSpatialiteQueryAlgorithm::processAlgorithm( const QVariant uri = QgsDataSourceUri( QStringLiteral( "dbname='%1'" ).arg( databaseUri ) ); } - feedback->pushInfo( databaseUri ); std::unique_ptr conn; try { From c4c27c68c909906ea2215bf96ce9cb4a56be04a7 Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Wed, 29 Jan 2025 15:28:50 +0100 Subject: [PATCH 07/81] [server][wms] Add displayName to GFI JSON response In the gray zone between a feature and a bugfix... Fixes #59353 --- src/server/services/wms/qgswmsrenderer.cpp | 28 ++++++++- .../test_qgsserver_wms_getfeatureinfo.py | 60 +++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/server/services/wms/qgswmsrenderer.cpp b/src/server/services/wms/qgswmsrenderer.cpp index d3749453ed660..185df933ad5b6 100644 --- a/src/server/services/wms/qgswmsrenderer.cpp +++ b/src/server/services/wms/qgswmsrenderer.cpp @@ -2810,6 +2810,7 @@ namespace QgsWms { "features", json::array() }, }; const bool withGeometry = ( QgsServerProjectUtils::wmsFeatureInfoAddWktGeometry( *mProject ) && mWmsParameters.withGeometry() ); + const bool withDisplayName = mWmsParameters.withDisplayName(); const QDomNodeList layerList = doc.elementsByTagName( QStringLiteral( "Layer" ) ); for ( int i = 0; i < layerList.size(); ++i ) @@ -2841,6 +2842,7 @@ namespace QgsWms continue; QMap fidMap; + QMap fidDisplayNameMap; for ( int j = 0; j < featuresNode.size(); ++j ) { @@ -2881,6 +2883,24 @@ namespace QgsWms feature.setGeometry( QgsGeometry::fromWkt( wkt ) ); } } + + // Note: this is the feature expression display name, not the field alias + if ( withDisplayName ) + { + QString displayName; + const QDomNodeList attrs = featureNode.elementsByTagName( "Attribute" ); + for ( int k = 0; k < attrs.count(); k++ ) + { + const QDomElement elm = attrs.at( k ).toElement(); + if ( elm.attribute( QStringLiteral( "name" ) ).compare( "displayName" ) == 0 ) + { + displayName = elm.attribute( "value" ); + break; + } + } + fidDisplayNameMap.insert( feature.id(), displayName ); + } + features << feature; // search attributes to export (one time only) @@ -2892,7 +2912,6 @@ namespace QgsWms { const QDomElement attributeElement = attributesNode.at( k ).toElement(); const QString fieldName = attributeElement.attribute( QStringLiteral( "name" ) ); - attributes << feature.fieldNameIndex( fieldName ); } } @@ -2909,7 +2928,12 @@ namespace QgsWms for ( const auto &feature : std::as_const( features ) ) { const QString id = QStringLiteral( "%1.%2" ).arg( layerName ).arg( fidMap.value( feature.id() ) ); - json["features"].push_back( exporter.exportFeatureToJsonObject( feature, QVariantMap(), id ) ); + QVariantMap extraProperties; + if ( withDisplayName ) + { + extraProperties.insert( QStringLiteral( "display_name" ), fidDisplayNameMap.value( feature.id() ) ); + } + json["features"].push_back( exporter.exportFeatureToJsonObject( feature, extraProperties, id ) ); } } else // raster layer diff --git a/tests/src/python/test_qgsserver_wms_getfeatureinfo.py b/tests/src/python/test_qgsserver_wms_getfeatureinfo.py index 4b05eb0a6459f..d0f7813d11cb4 100644 --- a/tests/src/python/test_qgsserver_wms_getfeatureinfo.py +++ b/tests/src/python/test_qgsserver_wms_getfeatureinfo.py @@ -1496,6 +1496,66 @@ def test_getfeatureinfo_form_config(self): self.assertNotIn("name_xyz", body) self.assertIn("id_xyz", body) + def test_getfeatureinfo_display_name(self): + """Test issue GH #59353""" + + # create a memory layer with points + fields = QgsFields() + fields.append(QgsField("id_xyz", QVariant.Int)) + fields.append(QgsField("name_xyz", QVariant.String)) + layer = QgsMemoryProviderUtils.createMemoryLayer( + "points", + fields, + QgsWkbTypes.Point, + QgsCoordinateReferenceSystem("EPSG:4326"), + ) + layer.setDisplayExpression("name_xyz || ' (' || id_xyz || ')'") + + provider = layer.dataProvider() + self.assertTrue(layer.isValid()) + + # add some features + f = QgsFeature(fields) + f.setAttribute("id_xyz", 1) + f.setAttribute("name_xyz", "point1") + f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(0, 0))) + provider.addFeature(f) + + f = QgsFeature(fields) + f.setAttribute("id_xyz", 2) + f.setAttribute("name_xyz", "point2") + f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 1))) + provider.addFeature(f) + + f = QgsFeature(fields) + f.setAttribute("id_xyz", 3) + f.setAttribute("name_xyz", "point3") + f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-1, -1))) + provider.addFeature(f) + + project = QgsProject() + project.addMapLayer(layer) + + # set up the WMS server + server = QgsServer() + request = QgsServerRequest() + w = 10 + w2 = int(w / 2) + + # Note: not implemented for , 'application/vnd.ogc.gml' + for info_format in ["text/plain", "application/json", "text/xml"]: + + request.setUrl( + QUrl( + f"?SERVICE=WMS&REQUEST=GetFeatureInfo&LAYERS=points&QUERY_LAYERS=points&INFO_FORMAT={info_format}&FEATURE_COUNT=1&WIDTH={w}&HEIGHT={w}&CRS=EPSG:4326&STYLES=&WITH_DISPLAY_NAME=true&BBOX=-1,-1,1,1&X={w2}&Y={w2}&VERSION=1.3.0" + ) + ) + response = QgsBufferServerResponse() + + server.handleRequest(request, response, project) + body = response.body().data().decode("utf8").replace("\n", " ") + self.assertIn("point1 (1)", body) + if __name__ == "__main__": unittest.main() From bb59344c4e257e4fc33b3cb29ff2a07bc0b2d5a9 Mon Sep 17 00:00:00 2001 From: Alessandro Pasotti Date: Wed, 29 Jan 2025 17:23:02 +0100 Subject: [PATCH 08/81] [raster][opencl] Fix raster calc Uint16 (#60339) Fixes #60077 --- src/analysis/raster/qgsrastercalculator.cpp | 6 +- .../src/analysis/testqgsrastercalculator.cpp | 145 ++++++++++++++++++ 2 files changed, 148 insertions(+), 3 deletions(-) diff --git a/src/analysis/raster/qgsrastercalculator.cpp b/src/analysis/raster/qgsrastercalculator.cpp index 1203d36085745..dbd91e0d2b7c3 100644 --- a/src/analysis/raster/qgsrastercalculator.cpp +++ b/src/analysis/raster/qgsrastercalculator.cpp @@ -446,10 +446,10 @@ QgsRasterCalculator::Result QgsRasterCalculator::processCalculationGPU( std::uni entry.typeName = QStringLiteral( "unsigned char" ); break; case Qgis::DataType::Int8: - entry.typeName = QStringLiteral( "signed char" ); + entry.typeName = QStringLiteral( "char" ); break; case Qgis::DataType::UInt16: - entry.typeName = QStringLiteral( "unsigned int" ); + entry.typeName = QStringLiteral( "unsigned short" ); break; case Qgis::DataType::Int16: entry.typeName = QStringLiteral( "short" ); @@ -544,7 +544,7 @@ QgsRasterCalculator::Result QgsRasterCalculator::processCalculationGPU( std::uni programTemplate = programTemplate.replace( QLatin1String( "##EXPRESSION##" ), cExpression ); programTemplate = programTemplate.replace( QLatin1String( "##EXPRESSION_ORIGINAL##" ), calcNode->toString() ); - //qDebug() << programTemplate; + // qDebug() << programTemplate; // Create a program from the kernel source cl::Program program( QgsOpenClUtils::buildProgram( programTemplate, QgsOpenClUtils::ExceptionBehavior::Throw ) ); diff --git a/tests/src/analysis/testqgsrastercalculator.cpp b/tests/src/analysis/testqgsrastercalculator.cpp index 1dee37ea09223..7545c85e751cf 100644 --- a/tests/src/analysis/testqgsrastercalculator.cpp +++ b/tests/src/analysis/testqgsrastercalculator.cpp @@ -25,6 +25,7 @@ Email : nyall dot dawson at gmail dot com #include "qgsrastermatrix.h" #include "qgsapplication.h" #include "qgsproject.h" +#include "qgsgdalutils.h" #include @@ -61,6 +62,8 @@ class TestQgsRasterCalculator : public QgsTest void calcWithLayers(); void calcWithReprojectedLayers(); + void calcWithDataType(); + void calcWithDataType_data(); void errors(); void toString(); @@ -537,6 +540,148 @@ void TestQgsRasterCalculator::calcWithReprojectedLayers() delete block; } + +void TestQgsRasterCalculator::calcWithDataType_data() +{ + QTest::addColumn( "dataType" ); + QTest::addColumn( "useOpenCL" ); + + QTest::newRow( "UInt16 without OpenCL" ) << static_cast( GDT_UInt16 ) << false; + QTest::newRow( "Byte without OpenCL" ) << static_cast( GDT_Byte ) << false; +#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 ) + QTest::newRow( "Int8 without OpenCL" ) << static_cast( GDT_Int8 ) << false; +#endif + QTest::newRow( "Int16 without OpenCL" ) << static_cast( GDT_Int16 ) << false; + QTest::newRow( "Int32 without OpenCL" ) << static_cast( GDT_Int32 ) << false; + QTest::newRow( "UInt32 without OpenCL" ) << static_cast( GDT_UInt32 ) << false; + QTest::newRow( "Float32 without OpenCL" ) << static_cast( GDT_Float32 ) << false; + QTest::newRow( "Float64 without OpenCL" ) << static_cast( GDT_Float64 ) << false; + +#ifdef HAVE_OPENCL + QTest::newRow( "UInt16 with OpenCL" ) << static_cast( GDT_UInt16 ) << true; + QTest::newRow( "Byte with OpenCL" ) << static_cast( GDT_Byte ) << true; +#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 ) + QTest::newRow( "Int8 with OpenCL" ) << static_cast( GDT_Int8 ) << true; +#endif + QTest::newRow( "Int16 with OpenCL" ) << static_cast( GDT_Int16 ) << true; + QTest::newRow( "Int32 with OpenCL" ) << static_cast( GDT_Int32 ) << true; + QTest::newRow( "UInt32 with OpenCL" ) << static_cast( GDT_UInt32 ) << true; + QTest::newRow( "Float32 with OpenCL" ) << static_cast( GDT_Float32 ) << true; + QTest::newRow( "Float64 with OpenCL" ) << static_cast( GDT_Float64 ) << true; +#endif +} +void TestQgsRasterCalculator::calcWithDataType() +{ + QFETCH( int, dataType ); + QFETCH( bool, useOpenCL ); + +#ifdef HAVE_OPENCL + if ( QgsOpenClUtils::available() && useOpenCL ) + QgsOpenClUtils::setEnabled( useOpenCL ); + else + QgsOpenClUtils::setEnabled( false ); + +#endif + + QTemporaryDir tempDir; + const QString dirPath = tempDir.path(); + const QString tempInputFilePath = dirPath + "/temp_input.tif"; + const QString tempResultFilePath = dirPath + "/result.tif"; + + QgsRectangle extent = QgsRectangle::fromCenterAndSize( { 0, 0 }, 2, 2 ); + + QgsCoordinateReferenceSystem crs( QStringLiteral( "EPSG:32633" ) ); + + const GDALDataType gdalDataType { static_cast( dataType ) }; + + { + const gdal::dataset_unique_ptr hSrcDS( QgsGdalUtils::createSingleBandTiffDataset( tempInputFilePath, gdalDataType, extent, 2, 2, crs ) ); + // Get first band + auto hBand = GDALGetRasterBand( hSrcDS.get(), 1 ); + switch ( gdalDataType ) + { + case GDT_Byte: + { + unsigned char data[4] = { 1, 2, 3, 4 }; + QCOMPARE( GDALRasterIO( hBand, GF_Write, 0, 0, 2, 2, data, 2, 2, gdalDataType, 0, 0 ), CE_None ); + break; + } +#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 ) + case GDT_Int8: + { + char data8[4] = { 1, 2, 3, 4 }; + QCOMPARE( GDALRasterIO( hBand, GF_Write, 0, 0, 2, 2, data8, 2, 2, gdalDataType, 0, 0 ), CE_None ); + break; + } +#endif + case GDT_UInt16: + { + unsigned short data16[4] = { 1, 2, 3, 4 }; + QCOMPARE( GDALRasterIO( hBand, GF_Write, 0, 0, 2, 2, data16, 2, 2, gdalDataType, 0, 0 ), CE_None ); + break; + } + case GDT_Int16: + { + short data16s[4] = { 1, 2, 3, 4 }; + QCOMPARE( GDALRasterIO( hBand, GF_Write, 0, 0, 2, 2, data16s, 2, 2, gdalDataType, 0, 0 ), CE_None ); + break; + } + case GDT_Int32: + { + int data32[4] = { 1, 2, 3, 4 }; + QCOMPARE( GDALRasterIO( hBand, GF_Write, 0, 0, 2, 2, data32, 2, 2, gdalDataType, 0, 0 ), CE_None ); + break; + } + case GDT_UInt32: + { + unsigned int data32u[4] = { 1, 2, 3, 4 }; + QCOMPARE( GDALRasterIO( hBand, GF_Write, 0, 0, 2, 2, data32u, 2, 2, gdalDataType, 0, 0 ), CE_None ); + break; + } + case GDT_Float32: + { + float data32f[4] = { 1, 2, 3, 4 }; + QCOMPARE( GDALRasterIO( hBand, GF_Write, 0, 0, 2, 2, data32f, 2, 2, gdalDataType, 0, 0 ), CE_None ); + break; + } + case GDT_Float64: + { + double data64[4] = { 1, 2, 3, 4 }; + QCOMPARE( GDALRasterIO( hBand, GF_Write, 0, 0, 2, 2, data64, 2, 2, gdalDataType, 0, 0 ), CE_None ); + break; + } + default: + QVERIFY( false ); + break; + } + GDALFlushCache( hSrcDS.get() ); + } + + // Load 16 bit usigned raster + std::unique_ptr demRasterLayer = std::make_unique( tempInputFilePath, QStringLiteral( "dem" ) ); + + QgsRasterCalculatorEntry entry1; + entry1.bandNumber = 1; + entry1.raster = demRasterLayer.get(); + entry1.ref = QStringLiteral( "dem@1" ); + QVector entries; + entries << entry1; + + QgsRasterCalculator rc( QStringLiteral( "\"dem@1\" * 2" ), tempResultFilePath, QStringLiteral( "GTiff" ), extent, crs, 2, 2, entries, QgsProject::instance()->transformContext() ); + QCOMPARE( static_cast( rc.processCalculation() ), 0 ); + + std::unique_ptr result = std::make_unique( tempResultFilePath, QStringLiteral( "result" ) ); + QCOMPARE( result->width(), 2 ); + QCOMPARE( result->height(), 2 ); + std::unique_ptr block; + block.reset( result->dataProvider()->block( 1, extent, 2, 2 ) ); + QCOMPARE( block->value( 0, 0 ), 2 ); + QCOMPARE( block->value( 0, 1 ), 4 ); + QCOMPARE( block->value( 1, 0 ), 6 ); + QCOMPARE( block->value( 1, 1 ), 8 ); +} + + void TestQgsRasterCalculator::findNodes() { std::unique_ptr calcNode; From 08ba10b929a6f2f2039f0b24b13ba94be1e19e60 Mon Sep 17 00:00:00 2001 From: Harrissou Sant-anna Date: Wed, 29 Jan 2025 22:05:31 +0100 Subject: [PATCH 09/81] [mesh] Name the "Remove datasets" button --- src/ui/mesh/qgsmeshdatasetgrouptreewidgetbase.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ui/mesh/qgsmeshdatasetgrouptreewidgetbase.ui b/src/ui/mesh/qgsmeshdatasetgrouptreewidgetbase.ui index af99612eb5feb..f61e4ec2205d5 100644 --- a/src/ui/mesh/qgsmeshdatasetgrouptreewidgetbase.ui +++ b/src/ui/mesh/qgsmeshdatasetgrouptreewidgetbase.ui @@ -68,6 +68,9 @@ + + Remove Extra Dataset from Mesh + false From 34e76d388ee8684cbb152f26c33d1405adc5e41c Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Mon, 27 Jan 2025 12:26:10 +0000 Subject: [PATCH 10/81] add test for QgsIdwInterpolator --- tests/src/python/CMakeLists.txt | 1 + .../src/python/test_analysis_interpolation.py | 98 +++++++++++++++++++ tests/testdata/analysis/idw_interpolation.asc | 12 +++ tests/testdata/analysis/idw_interpolation.prj | 1 + 4 files changed, 112 insertions(+) create mode 100644 tests/src/python/test_analysis_interpolation.py create mode 100644 tests/testdata/analysis/idw_interpolation.asc create mode 100644 tests/testdata/analysis/idw_interpolation.prj diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt index eb1a995bb715b..be46cfd16125f 100644 --- a/tests/src/python/CMakeLists.txt +++ b/tests/src/python/CMakeLists.txt @@ -404,6 +404,7 @@ ADD_PYTHON_TEST(PyQgsAttributeEditorAction test_qgsattributeeditoraction.py) ADD_PYTHON_TEST(PyQgsVectorTile test_qgsvectortile.py) ADD_PYTHON_TEST(PyQgsVtpk test_qgsvtpk.py) ADD_PYTHON_TEST(PyQgsProcessingAlgsGdalGdalUtils test_processing_algs_gdal_gdalutils.py) +ADD_PYTHON_TEST(PyQgsInterpolation test_analysis_interpolation.py) if (NOT WIN32) ADD_PYTHON_TEST(PyQgsLogger test_qgslogger.py) diff --git a/tests/src/python/test_analysis_interpolation.py b/tests/src/python/test_analysis_interpolation.py new file mode 100644 index 0000000000000..155765471859b --- /dev/null +++ b/tests/src/python/test_analysis_interpolation.py @@ -0,0 +1,98 @@ +""" +*************************************************************************** + test_analysis_interpolation.py + --------------------- + Date : January 2025 + Copyright : (C) 2025 by Alexander Bruy + Email : alexander dot bruy at gmail.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. * +* * +*************************************************************************** +""" + +__author__ = "Alexander Bruy" +__date__ = "January 2025" +__copyright__ = "(C) 2025, Alexander Bruy" + +import os +import math +import tempfile + +from qgis.core import ( + Qgis, + QgsCoordinateTransformContext, + QgsVectorLayer, + QgsRasterChecker, +) +from qgis.analysis import ( + QgsInterpolator, + QgsIDWInterpolator, + QgsGridFileWriter, +) + +import unittest +from qgis.testing import QgisTestCase + +from utilities import unitTestDataPath, start_app + +TEST_DATA_DIR = unitTestDataPath() +start_app() + + +class TestInterpolation(QgisTestCase): + + def __init__(self, methodName): + QgisTestCase.__init__(self, methodName) + self.report = "

Python Raster Analysis Interpolation Tests

\n" + + def test_idw_interpolator(self): + layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr" + ) + self.assertTrue(layer.isValid()) + + pixel_size = 5 + extent = layer.extent() + context = QgsCoordinateTransformContext() + + cols = max(math.ceil(extent.width() / pixel_size), 1) + rows = max(math.ceil(extent.height() / pixel_size), 1) + + data = QgsInterpolator.LayerData() + data.source = layer + data.sourceType = QgsInterpolator.SourceType.SourcePoints + data.transformContext = context + data.valueSource = QgsInterpolator.ValueSource.ValueAttribute + data.interpolationAttribute = 3 + + interpolator = QgsIDWInterpolator([data]) + interpolator.setDistanceCoefficient(2.0) + + output_file = os.path.join(tempfile.gettempdir(), "idw_interpolation.asc") + + writer = QgsGridFileWriter(interpolator, output_file, extent, cols, rows) + writer.writeFile() + + checker = QgsRasterChecker() + ok = checker.runTest( + "gdal", + output_file, + "gdal", + os.path.join(TEST_DATA_DIR, "analysis", "idw_interpolation.asc"), + ) + self.report += checker.report() + + report_file = os.path.join(tempfile.gettempdir(), "idw_interpolation_test.html") + with open(report_file, "w", encoding="utf-8") as f: + f.write(self.report) + + self.assertTrue(ok) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/testdata/analysis/idw_interpolation.asc b/tests/testdata/analysis/idw_interpolation.asc new file mode 100644 index 0000000000000..36bf9e4b9f823 --- /dev/null +++ b/tests/testdata/analysis/idw_interpolation.asc @@ -0,0 +1,12 @@ +NCOLS 8 +NROWS 5 +XLLCORNER -118.88889 +YLLCORNER 22.800207 +DX 4.4444444 +DY 4.8143547 +NODATA_VALUE -9999 +2.0121718 2.0665639 2.1247411 2.3766166 2.215217 2.2060108 2.3460969 2.4281324 +1.9794705 2.9664047 1.9469473 2.5244787 2.0403568 2.6551881 2.47681 2.9540972 +1.7556216 1.2623123 1.3645298 1.6318147 1.1678245 1.6944965 1.4976418 2.3077948 +1.6575363 1.3857927 1.7369403 1.6948927 1.6519006 1.7477886 1.7252076 2.0989999 +1.747618 1.7597898 2.017072 2.0723577 1.9158142 1.8779713 1.9250969 2.0499401 diff --git a/tests/testdata/analysis/idw_interpolation.prj b/tests/testdata/analysis/idw_interpolation.prj new file mode 100644 index 0000000000000..5fbc831e74334 --- /dev/null +++ b/tests/testdata/analysis/idw_interpolation.prj @@ -0,0 +1 @@ +GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] From 03ac6f492a4f2a8d1fcb39af8df7596e8801b774 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Mon, 27 Jan 2025 12:54:47 +0000 Subject: [PATCH 11/81] add test for QgsTinInterpolator --- .../src/python/test_analysis_interpolation.py | 45 +++++++++++++++++++ tests/testdata/analysis/tin_interpolation.asc | 12 +++++ tests/testdata/analysis/tin_interpolation.prj | 1 + 3 files changed, 58 insertions(+) create mode 100644 tests/testdata/analysis/tin_interpolation.asc create mode 100644 tests/testdata/analysis/tin_interpolation.prj diff --git a/tests/src/python/test_analysis_interpolation.py b/tests/src/python/test_analysis_interpolation.py index 155765471859b..2b5a451038e9b 100644 --- a/tests/src/python/test_analysis_interpolation.py +++ b/tests/src/python/test_analysis_interpolation.py @@ -32,6 +32,7 @@ from qgis.analysis import ( QgsInterpolator, QgsIDWInterpolator, + QgsTinInterpolator, QgsGridFileWriter, ) @@ -93,6 +94,50 @@ def test_idw_interpolator(self): self.assertTrue(ok) + def test_tin_interpolator(self): + layer = QgsVectorLayer( + os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr" + ) + self.assertTrue(layer.isValid()) + + pixel_size = 5 + extent = layer.extent() + context = QgsCoordinateTransformContext() + + cols = max(math.ceil(extent.width() / pixel_size), 1) + rows = max(math.ceil(extent.height() / pixel_size), 1) + + data = QgsInterpolator.LayerData() + data.source = layer + data.sourceType = QgsInterpolator.SourceType.SourcePoints + data.transformContext = context + data.valueSource = QgsInterpolator.ValueSource.ValueAttribute + data.interpolationAttribute = 3 + + interpolator = QgsTinInterpolator( + [data], QgsTinInterpolator.TinInterpolation.Linear + ) + + output_file = os.path.join(tempfile.gettempdir(), "tin_interpolation.asc") + + writer = QgsGridFileWriter(interpolator, output_file, extent, cols, rows) + writer.writeFile() + + checker = QgsRasterChecker() + ok = checker.runTest( + "gdal", + output_file, + "gdal", + os.path.join(TEST_DATA_DIR, "analysis", "tin_interpolation.asc"), + ) + self.report += checker.report() + + report_file = os.path.join(tempfile.gettempdir(), "tin_interpolation_test.html") + with open(report_file, "w", encoding="utf-8") as f: + f.write(self.report) + + self.assertTrue(ok) + if __name__ == "__main__": unittest.main() diff --git a/tests/testdata/analysis/tin_interpolation.asc b/tests/testdata/analysis/tin_interpolation.asc new file mode 100644 index 0000000000000..4f46319640b89 --- /dev/null +++ b/tests/testdata/analysis/tin_interpolation.asc @@ -0,0 +1,12 @@ +NCOLS 8 +NROWS 5 +XLLCORNER -118.88889 +YLLCORNER 22.800207 +DX 4.4444444 +DY 4.8143547 +NODATA_VALUE -9999 +-9999 -9999 -9999 2.0980652 2.3606286 2.2927486 -9999 -9999 +-9999 2.9180237 2.725426 2.5698732 1.8980129 2.5750412 2.8987709 -9999 +-9999 1 1.0520833 1.60625 1.1508401 1.122037 1.2837485 2.2915296 +-9999 -9999 1.8246582 1.4968504 1.3897458 1.3489822 -9999 -9999 +-9999 -9999 -9999 1.8401575 -9999 -9999 -9999 -9999 diff --git a/tests/testdata/analysis/tin_interpolation.prj b/tests/testdata/analysis/tin_interpolation.prj new file mode 100644 index 0000000000000..5fbc831e74334 --- /dev/null +++ b/tests/testdata/analysis/tin_interpolation.prj @@ -0,0 +1 @@ +GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] From 2aa6c5dec25226fcb55f2fb3ab4b4594e64cf9a6 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Mon, 27 Jan 2025 14:18:11 +0000 Subject: [PATCH 12/81] use QGIS API to write raster files in QgsGridFileWriter (fix #56653) --- .../interpolation/qgsgridfilewriter.cpp | 96 +++++++----------- .../interpolation/qgsgridfilewriter.h | 2 - .../src/python/test_analysis_interpolation.py | 8 +- tests/testdata/analysis/idw_interpolation.asc | 12 --- tests/testdata/analysis/idw_interpolation.prj | 1 - tests/testdata/analysis/idw_interpolation.tif | Bin 0 -> 902 bytes tests/testdata/analysis/tin_interpolation.asc | 12 --- tests/testdata/analysis/tin_interpolation.prj | 1 - tests/testdata/analysis/tin_interpolation.tif | Bin 0 -> 902 bytes 9 files changed, 39 insertions(+), 93 deletions(-) delete mode 100644 tests/testdata/analysis/idw_interpolation.asc delete mode 100644 tests/testdata/analysis/idw_interpolation.prj create mode 100644 tests/testdata/analysis/idw_interpolation.tif delete mode 100644 tests/testdata/analysis/tin_interpolation.asc delete mode 100644 tests/testdata/analysis/tin_interpolation.prj create mode 100644 tests/testdata/analysis/tin_interpolation.tif diff --git a/src/analysis/interpolation/qgsgridfilewriter.cpp b/src/analysis/interpolation/qgsgridfilewriter.cpp index 838505c80c861..abd92e9f7be3a 100644 --- a/src/analysis/interpolation/qgsgridfilewriter.cpp +++ b/src/analysis/interpolation/qgsgridfilewriter.cpp @@ -19,7 +19,9 @@ #include "qgsinterpolator.h" #include "qgsvectorlayer.h" #include "qgsfeedback.h" -#include +#include "qgsrasterfilewriter.h" +#include "qgsrasterdataprovider.h" +#include "qgsrasterblock.h" #include QgsGridFileWriter::QgsGridFileWriter( QgsInterpolator *i, const QString &outputPath, const QgsRectangle &extent, int nCols, int nRows ) @@ -34,95 +36,67 @@ QgsGridFileWriter::QgsGridFileWriter( QgsInterpolator *i, const QString &outputP int QgsGridFileWriter::writeFile( QgsFeedback *feedback ) { - QFile outputFile( mOutputFilePath ); + const QFileInfo fi( mOutputFilePath ); + const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() ); + + QgsInterpolator::LayerData ld = mInterpolator->layerData().at( 0 ); + const QgsCoordinateReferenceSystem crs = ld.source->sourceCrs(); - if ( !outputFile.open( QFile::WriteOnly | QIODevice::Truncate ) ) + std::unique_ptr writer = std::make_unique( mOutputFilePath ); + writer->setOutputProviderKey( QStringLiteral( "gdal" ) ); + writer->setOutputFormat( outputFormat ); + + std::unique_ptr provider( writer->createOneBandRaster( Qgis::DataType::Float32, mNumColumns, mNumRows, mInterpolationExtent, crs ) ); + if ( !provider ) { + QgsDebugMsgLevel( QStringLiteral( "Could not create raster output: %1" ).arg( mOutputFilePath ), 2 ); return 1; } - - if ( !mInterpolator ) + if ( !provider->isValid() ) { - outputFile.remove(); + QgsDebugMsgLevel( QStringLiteral( "Could not create raster output: %1: %2" ).arg( mOutputFilePath, provider->error().message( QgsErrorMessage::Text ) ), 2 ); return 2; } - QTextStream outStream( &outputFile ); -#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) - outStream.setCodec( "UTF-8" ); -#endif - outStream.setRealNumberPrecision( 8 ); - writeHeader( outStream ); + provider->setNoDataValue( 1, -9999 ); double currentYValue = mInterpolationExtent.yMaximum() - mCellSizeY / 2.0; //calculate value in the center of the cell double currentXValue; double interpolatedValue; - for ( int i = 0; i < mNumRows; ++i ) + const double step = mNumRows > 0 ? 100.0 / mNumRows : 1; + for ( int row = 0; row < mNumRows; row++ ) { + if ( feedback && feedback->isCanceled() ) + { + break; + } + currentXValue = mInterpolationExtent.xMinimum() + mCellSizeX / 2.0; //calculate value in the center of the cell - for ( int j = 0; j < mNumColumns; ++j ) + + QgsRasterBlock block( Qgis::DataType::Float32, mNumColumns, 1 ); + + std::vector float32Row( mNumColumns ); + for ( int col = 0; col < mNumColumns; col++ ) { if ( mInterpolator->interpolatePoint( currentXValue, currentYValue, interpolatedValue, feedback ) == 0 ) { - outStream << interpolatedValue << ' '; + float32Row[col] = interpolatedValue; } else { - outStream << "-9999 "; + float32Row[col] = -9999; } currentXValue += mCellSizeX; } - - outStream << Qt::endl; + block.setData( QByteArray( reinterpret_cast( float32Row.data() ), QgsRasterBlock::typeSize( Qgis::DataType::Float32 ) * mNumColumns ) ); + provider->writeBlock( &block, 1, 0, row ); currentYValue -= mCellSizeY; - if ( feedback ) { - if ( feedback->isCanceled() ) - { - outputFile.remove(); - return 3; - } - feedback->setProgress( 100.0 * i / static_cast( mNumRows ) ); + feedback->setProgress( row * step ); } } - // create prj file - QgsInterpolator::LayerData ld; - ld = mInterpolator->layerData().at( 0 ); - QgsFeatureSource *source = ld.source; - const QString crs = source->sourceCrs().toWkt(); - const QFileInfo fi( mOutputFilePath ); - const QString fileName = fi.absolutePath() + '/' + fi.completeBaseName() + ".prj"; - QFile prjFile( fileName ); - if ( !prjFile.open( QFile::WriteOnly | QIODevice::Truncate ) ) - { - return 1; - } - QTextStream prjStream( &prjFile ); - prjStream << crs; - prjStream << Qt::endl; - prjFile.close(); - - return 0; -} - -int QgsGridFileWriter::writeHeader( QTextStream &outStream ) -{ - outStream << "NCOLS " << mNumColumns << Qt::endl; - outStream << "NROWS " << mNumRows << Qt::endl; - outStream << "XLLCORNER " << mInterpolationExtent.xMinimum() << Qt::endl; - outStream << "YLLCORNER " << mInterpolationExtent.yMinimum() << Qt::endl; - if ( mCellSizeX == mCellSizeY ) //standard way - { - outStream << "CELLSIZE " << mCellSizeX << Qt::endl; - } - else //this is supported by GDAL but probably not by other products - { - outStream << "DX " << mCellSizeX << Qt::endl; - outStream << "DY " << mCellSizeY << Qt::endl; - } - outStream << "NODATA_VALUE -9999" << Qt::endl; return 0; } diff --git a/src/analysis/interpolation/qgsgridfilewriter.h b/src/analysis/interpolation/qgsgridfilewriter.h index 8f408c0a7c23a..58c41e8e552c4 100644 --- a/src/analysis/interpolation/qgsgridfilewriter.h +++ b/src/analysis/interpolation/qgsgridfilewriter.h @@ -56,8 +56,6 @@ class ANALYSIS_EXPORT QgsGridFileWriter private: QgsGridFileWriter() = delete; - int writeHeader( QTextStream &outStream ); - QgsInterpolator *mInterpolator = nullptr; QString mOutputFilePath; QgsRectangle mInterpolationExtent; diff --git a/tests/src/python/test_analysis_interpolation.py b/tests/src/python/test_analysis_interpolation.py index 2b5a451038e9b..bf0bcfbd54074 100644 --- a/tests/src/python/test_analysis_interpolation.py +++ b/tests/src/python/test_analysis_interpolation.py @@ -74,7 +74,7 @@ def test_idw_interpolator(self): interpolator = QgsIDWInterpolator([data]) interpolator.setDistanceCoefficient(2.0) - output_file = os.path.join(tempfile.gettempdir(), "idw_interpolation.asc") + output_file = os.path.join(tempfile.gettempdir(), "idw_interpolation.tif") writer = QgsGridFileWriter(interpolator, output_file, extent, cols, rows) writer.writeFile() @@ -84,7 +84,7 @@ def test_idw_interpolator(self): "gdal", output_file, "gdal", - os.path.join(TEST_DATA_DIR, "analysis", "idw_interpolation.asc"), + os.path.join(TEST_DATA_DIR, "analysis", "idw_interpolation.tif"), ) self.report += checker.report() @@ -118,7 +118,7 @@ def test_tin_interpolator(self): [data], QgsTinInterpolator.TinInterpolation.Linear ) - output_file = os.path.join(tempfile.gettempdir(), "tin_interpolation.asc") + output_file = os.path.join(tempfile.gettempdir(), "tin_interpolation.tif") writer = QgsGridFileWriter(interpolator, output_file, extent, cols, rows) writer.writeFile() @@ -128,7 +128,7 @@ def test_tin_interpolator(self): "gdal", output_file, "gdal", - os.path.join(TEST_DATA_DIR, "analysis", "tin_interpolation.asc"), + os.path.join(TEST_DATA_DIR, "analysis", "tin_interpolation.tif"), ) self.report += checker.report() diff --git a/tests/testdata/analysis/idw_interpolation.asc b/tests/testdata/analysis/idw_interpolation.asc deleted file mode 100644 index 36bf9e4b9f823..0000000000000 --- a/tests/testdata/analysis/idw_interpolation.asc +++ /dev/null @@ -1,12 +0,0 @@ -NCOLS 8 -NROWS 5 -XLLCORNER -118.88889 -YLLCORNER 22.800207 -DX 4.4444444 -DY 4.8143547 -NODATA_VALUE -9999 -2.0121718 2.0665639 2.1247411 2.3766166 2.215217 2.2060108 2.3460969 2.4281324 -1.9794705 2.9664047 1.9469473 2.5244787 2.0403568 2.6551881 2.47681 2.9540972 -1.7556216 1.2623123 1.3645298 1.6318147 1.1678245 1.6944965 1.4976418 2.3077948 -1.6575363 1.3857927 1.7369403 1.6948927 1.6519006 1.7477886 1.7252076 2.0989999 -1.747618 1.7597898 2.017072 2.0723577 1.9158142 1.8779713 1.9250969 2.0499401 diff --git a/tests/testdata/analysis/idw_interpolation.prj b/tests/testdata/analysis/idw_interpolation.prj deleted file mode 100644 index 5fbc831e74334..0000000000000 --- a/tests/testdata/analysis/idw_interpolation.prj +++ /dev/null @@ -1 +0,0 @@ -GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] diff --git a/tests/testdata/analysis/idw_interpolation.tif b/tests/testdata/analysis/idw_interpolation.tif new file mode 100644 index 0000000000000000000000000000000000000000..d961111262f46b84e2428e7c331aaa27301158aa GIT binary patch literal 902 zcmebD)MDUcVqg$pU|?isU}Rum-~eJqD4P|?W`eR6fNW+c8>Eg6i7m*;0@e!@W)MXZ z7lX1v=7=MykwH=u3}rI|)$ld*Fo5WDK-|>A!@vflp8@guc4h_zAT0*8ctbl61JJ;M+TL$p1%=zF{)_Q1}Q!UA*i-QnsP z!MK-hY~e0ht@P{2e0_Q z_LFbgI!rSCY0p1V(ZO^olf$fcnhty|at`nKZ5>Q^Jg_gGywLvTigosW_b=GHRZq2d zetN@x*QWjUFEEg6i7m*;0@e!@W)MXZ z7lX1v=7=MykwH=u3}rI|)$ld*Fo5WDK-|>A!@vflp8@guc4h_zAT0*8ctbl61JJ;M+TL$p1%=zF{)_Q1}Q!UA*i-QnsP z!MFxbc(gW=6?Yz|!_;tr{MgdAXEAo|$>D~H5fJ%_UuDh^_w zKG|2DRdFb9wM3|4Xs}YL*dAT4F~kLd-lIGfreI-~lk2VX5E;kPS-(8o(q1O9dG~ dHY^oX0NIU8n82x~0hEk@V6dkMT}vQf008e{h~oeN literal 0 HcmV?d00001 From 47764783549ae7b9b7d3bb938bd3450544d1f278 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Tue, 28 Jan 2025 13:39:45 +0000 Subject: [PATCH 13/81] update expected raster hashes --- .../tests/testdata/qgis_algorithm_tests2.yaml | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests2.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests2.yaml index 7a4d24eed45b5..dd65231793fef 100644 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests2.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests2.yaml @@ -14,9 +14,7 @@ tests: results: OUTPUT: hash: - - bfb3616a73065c0cb41eb1c5c1e9e8812fe1c63019a6177adb1dfe3e - - 19bbd79d15b0ba7dbde05665d559e9806fdb1cd579df9222f9cc4d92 - - 3dfa1e041f33a72abf72d2d706c03e11fa5274f152dec1db1661b8e0 + - e277a6774c489ee965421fe102780275163229b9407d5e33d3e268e5 type: rasterhash - algorithm: qgis:tininterpolation @@ -31,9 +29,7 @@ tests: results: OUTPUT: hash: - - bfb3616a73065c0cb41eb1c5c1e9e8812fe1c63019a6177adb1dfe3e - - 19bbd79d15b0ba7dbde05665d559e9806fdb1cd579df9222f9cc4d92 - - 3dfa1e041f33a72abf72d2d706c03e11fa5274f152dec1db1661b8e0 + - e277a6774c489ee965421fe102780275163229b9407d5e33d3e268e5 type: rasterhash - algorithm: qgis:tininterpolation @@ -48,9 +44,7 @@ tests: results: OUTPUT: hash: - - b8e49813c507b73cb39a5ad904b2d302ccb25c591a2e577b6405f982 - - 19bbd79d15b0ba7dbde05665d559e9806fdb1cd579df9222f9cc4d92 - - 3dfa1e041f33a72abf72d2d706c03e11fa5274f152dec1db1661b8e0 + - e277a6774c489ee965421fe102780275163229b9407d5e33d3e268e5 type: rasterhash - algorithm: qgis:tininterpolation @@ -66,9 +60,7 @@ tests: results: OUTPUT: hash: - - bfb3616a73065c0cb41eb1c5c1e9e8812fe1c63019a6177adb1dfe3e - - 19bbd79d15b0ba7dbde05665d559e9806fdb1cd579df9222f9cc4d92 - - 3dfa1e041f33a72abf72d2d706c03e11fa5274f152dec1db1661b8e0 + - e277a6774c489ee965421fe102780275163229b9407d5e33d3e268e5 type: rasterhash - algorithm: qgis:tininterpolation @@ -84,9 +76,7 @@ tests: results: OUTPUT: hash: - - bfb3616a73065c0cb41eb1c5c1e9e8812fe1c63019a6177adb1dfe3e - - 19bbd79d15b0ba7dbde05665d559e9806fdb1cd579df9222f9cc4d92 - - 3dfa1e041f33a72abf72d2d706c03e11fa5274f152dec1db1661b8e0 + - e277a6774c489ee965421fe102780275163229b9407d5e33d3e268e5 type: rasterhash - algorithm: qgis:tininterpolation @@ -102,9 +92,7 @@ tests: results: OUTPUT: hash: - - b8e49813c507b73cb39a5ad904b2d302ccb25c591a2e577b6405f982 - - 19bbd79d15b0ba7dbde05665d559e9806fdb1cd579df9222f9cc4d92 - - 3dfa1e041f33a72abf72d2d706c03e11fa5274f152dec1db1661b8e0 + - e277a6774c489ee965421fe102780275163229b9407d5e33d3e268e5 type: rasterhash - algorithm: qgis:idwinterpolation @@ -119,8 +107,7 @@ tests: results: OUTPUT: hash: - - 55dfd0e0e5ea300d2314785ab6aa1f4d941a4506e63d0d9e2b84e959 - - b5fc06549f1b0ce3261f9fb8868bb6d082edcbfe409c89a82e2b7e7a + - 7836f01a89afbfdd865aaae9b57c602c96d629184adf1b6ea66ca127 type: rasterhash - algorithm: qgis:idwinterpolation @@ -135,8 +122,7 @@ tests: results: OUTPUT: hash: - - 55dfd0e0e5ea300d2314785ab6aa1f4d941a4506e63d0d9e2b84e959 - - b5fc06549f1b0ce3261f9fb8868bb6d082edcbfe409c89a82e2b7e7a + - 7836f01a89afbfdd865aaae9b57c602c96d629184adf1b6ea66ca127 type: rasterhash - algorithm: qgis:idwinterpolation @@ -151,8 +137,7 @@ tests: results: OUTPUT: hash: - - d53cd7327d53bd4b8fb2de8b206e5aa0a1366963f2b63f58c2b7926e - - b5fc06549f1b0ce3261f9fb8868bb6d082edcbfe409c89a82e2b7e7a + - 7836f01a89afbfdd865aaae9b57c602c96d629184adf1b6ea66ca127 type: rasterhash - algorithm: qgis:idwinterpolation @@ -168,8 +153,7 @@ tests: results: OUTPUT: hash: - - 55dfd0e0e5ea300d2314785ab6aa1f4d941a4506e63d0d9e2b84e959 - - b5fc06549f1b0ce3261f9fb8868bb6d082edcbfe409c89a82e2b7e7a + - 7836f01a89afbfdd865aaae9b57c602c96d629184adf1b6ea66ca127 type: rasterhash - algorithm: qgis:idwinterpolation @@ -185,8 +169,7 @@ tests: results: OUTPUT: hash: - - 55dfd0e0e5ea300d2314785ab6aa1f4d941a4506e63d0d9e2b84e959 - - b5fc06549f1b0ce3261f9fb8868bb6d082edcbfe409c89a82e2b7e7a + - 7836f01a89afbfdd865aaae9b57c602c96d629184adf1b6ea66ca127 type: rasterhash - algorithm: qgis:idwinterpolation @@ -202,8 +185,7 @@ tests: results: OUTPUT: hash: - - d53cd7327d53bd4b8fb2de8b206e5aa0a1366963f2b63f58c2b7926e - - b5fc06549f1b0ce3261f9fb8868bb6d082edcbfe409c89a82e2b7e7a + - 7836f01a89afbfdd865aaae9b57c602c96d629184adf1b6ea66ca127 type: rasterhash - algorithm: native:removenullgeometries From 77557643d22f2b50e51ae9aa0036331285c1cbb2 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Wed, 29 Jan 2025 08:31:01 +0000 Subject: [PATCH 14/81] move vector declaration outside of the loop --- src/analysis/interpolation/qgsgridfilewriter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/analysis/interpolation/qgsgridfilewriter.cpp b/src/analysis/interpolation/qgsgridfilewriter.cpp index abd92e9f7be3a..38bc26b429a2f 100644 --- a/src/analysis/interpolation/qgsgridfilewriter.cpp +++ b/src/analysis/interpolation/qgsgridfilewriter.cpp @@ -64,6 +64,7 @@ int QgsGridFileWriter::writeFile( QgsFeedback *feedback ) double currentXValue; double interpolatedValue; + std::vector float32Row( mNumColumns ); const double step = mNumRows > 0 ? 100.0 / mNumRows : 1; for ( int row = 0; row < mNumRows; row++ ) { @@ -73,10 +74,8 @@ int QgsGridFileWriter::writeFile( QgsFeedback *feedback ) } currentXValue = mInterpolationExtent.xMinimum() + mCellSizeX / 2.0; //calculate value in the center of the cell - QgsRasterBlock block( Qgis::DataType::Float32, mNumColumns, 1 ); - std::vector float32Row( mNumColumns ); for ( int col = 0; col < mNumColumns; col++ ) { if ( mInterpolator->interpolatePoint( currentXValue, currentYValue, interpolatedValue, feedback ) == 0 ) From d5edd0811fe6b98298bf51f52545156e9113a9e7 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 27 Jan 2025 22:36:58 +0100 Subject: [PATCH 15/81] webconnections saving as .xml: add a xmlns:x=y attribute when the http-header: prefix is used Fixes #60242 --- .../network/qgshttpheaders.sip.in | 12 +++++- .../network/qgshttpheaders.sip.in | 12 +++++- src/core/network/qgshttpheaders.cpp | 10 +++++ src/core/network/qgshttpheaders.h | 18 +++++++- src/gui/qgsmanageconnectionsdialog.cpp | 43 ++++++++++++++++--- tests/src/core/testqgshttpheaders.cpp | 5 ++- 6 files changed, 86 insertions(+), 14 deletions(-) diff --git a/python/PyQt6/core/auto_generated/network/qgshttpheaders.sip.in b/python/PyQt6/core/auto_generated/network/qgshttpheaders.sip.in index 3428ece4f42bb..c4e72e65a521c 100644 --- a/python/PyQt6/core/auto_generated/network/qgshttpheaders.sip.in +++ b/python/PyQt6/core/auto_generated/network/qgshttpheaders.sip.in @@ -109,15 +109,22 @@ KEY_REFERER value will be available at key "KEY_PREFIX+KEY_REFERER" and key "KEY :return: ``True`` if the update succeed %End - bool updateDomElement( QDomElement &el ) const; + bool updateDomElement( QDomElement &el ) const /Deprecated="Since 3.42. Will be removed in QGIS 4.0."/; %Docstring -Updates a ``map`` by adding all the HTTP headers +Updates a DOM element by adding all the HTTP headers KEY_REFERER value will be available at attribute "KEY_PREFIX+KEY_REFERER" and attribute "KEY_REFERER" (for backward compatibility) +:param el: DOM element + :return: ``True`` if the update succeed + +.. deprecated:: 3.42 + + Will be removed in QGIS 4.0. %End + void setFromSettings( const QgsSettings &settings, const QString &key = QString() ); %Docstring Loads headers from the ``settings`` @@ -185,6 +192,7 @@ Returns key/value pairs as strings separated by space }; + /************************************************************************ * This file has been generated automatically from * * * diff --git a/python/core/auto_generated/network/qgshttpheaders.sip.in b/python/core/auto_generated/network/qgshttpheaders.sip.in index 3428ece4f42bb..c4e72e65a521c 100644 --- a/python/core/auto_generated/network/qgshttpheaders.sip.in +++ b/python/core/auto_generated/network/qgshttpheaders.sip.in @@ -109,15 +109,22 @@ KEY_REFERER value will be available at key "KEY_PREFIX+KEY_REFERER" and key "KEY :return: ``True`` if the update succeed %End - bool updateDomElement( QDomElement &el ) const; + bool updateDomElement( QDomElement &el ) const /Deprecated="Since 3.42. Will be removed in QGIS 4.0."/; %Docstring -Updates a ``map`` by adding all the HTTP headers +Updates a DOM element by adding all the HTTP headers KEY_REFERER value will be available at attribute "KEY_PREFIX+KEY_REFERER" and attribute "KEY_REFERER" (for backward compatibility) +:param el: DOM element + :return: ``True`` if the update succeed + +.. deprecated:: 3.42 + + Will be removed in QGIS 4.0. %End + void setFromSettings( const QgsSettings &settings, const QString &key = QString() ); %Docstring Loads headers from the ``settings`` @@ -185,6 +192,7 @@ Returns key/value pairs as strings separated by space }; + /************************************************************************ * This file has been generated automatically from * * * diff --git a/src/core/network/qgshttpheaders.cpp b/src/core/network/qgshttpheaders.cpp index de9caeceeeeb5..01436e5799438 100644 --- a/src/core/network/qgshttpheaders.cpp +++ b/src/core/network/qgshttpheaders.cpp @@ -123,8 +123,18 @@ bool QgsHttpHeaders::updateMap( QVariantMap &map ) const bool QgsHttpHeaders::updateDomElement( QDomElement &el ) const { + QMap namespaceDeclarations; + return updateDomElement( el, namespaceDeclarations ); +} + +bool QgsHttpHeaders::updateDomElement( QDomElement &el, QMap &namespaceDeclarations ) const +{ + QString httpHeaderURIPrefix( QgsHttpHeaders::PARAM_PREFIX ); + httpHeaderURIPrefix.chop( 1 ); + for ( auto ite = mHeaders.constBegin(); ite != mHeaders.constEnd(); ++ite ) { + namespaceDeclarations.insert( httpHeaderURIPrefix, QStringLiteral( "https://qgis.org/" ) + httpHeaderURIPrefix ); el.setAttribute( QgsHttpHeaders::PARAM_PREFIX + ite.key().toUtf8(), ite.value().toString() ); } diff --git a/src/core/network/qgshttpheaders.h b/src/core/network/qgshttpheaders.h index 30e69ac705551..359e301bc40ca 100644 --- a/src/core/network/qgshttpheaders.h +++ b/src/core/network/qgshttpheaders.h @@ -126,13 +126,26 @@ class CORE_EXPORT QgsHttpHeaders bool updateMap( QVariantMap &map ) const; /** - * \brief Updates a \a map by adding all the HTTP headers + * \brief Updates a DOM element by adding all the HTTP headers * * KEY_REFERER value will be available at attribute "KEY_PREFIX+KEY_REFERER" and attribute "KEY_REFERER" (for backward compatibility) * + * \param el DOM element * \return TRUE if the update succeed + * \deprecated QGIS 3.42. Will be removed in QGIS 4.0. */ - bool updateDomElement( QDomElement &el ) const; + Q_DECL_DEPRECATED bool updateDomElement( QDomElement &el ) const SIP_DEPRECATED; + + /** + * \brief Updates a DOM element by adding all the HTTP headers + * + * KEY_REFERER value will be available at attribute "KEY_PREFIX+KEY_REFERER" and attribute "KEY_REFERER" (for backward compatibility) + * + * \param el DOM element + * \param[out] namespaceDeclarations Map of (prefix, URI) tuples for namespaces used by el. + * \return TRUE if the update succeed + */ + bool updateDomElement( QDomElement &el, QMap &namespaceDeclarations ) const SIP_SKIP; /** * \brief Loads headers from the \a settings @@ -211,3 +224,4 @@ class CORE_EXPORT QgsHttpHeaders }; #endif // QGSHTTPHEADERS_H + diff --git a/src/gui/qgsmanageconnectionsdialog.cpp b/src/gui/qgsmanageconnectionsdialog.cpp index dd0460ae00014..59bed6444fd7e 100644 --- a/src/gui/qgsmanageconnectionsdialog.cpp +++ b/src/gui/qgsmanageconnectionsdialog.cpp @@ -461,6 +461,14 @@ bool QgsManageConnectionsDialog::populateConnections() return true; } +static void addNamespaceDeclarations( QDomElement &root, const QMap &namespaceDeclarations ) +{ + for ( auto it = namespaceDeclarations.begin(); it != namespaceDeclarations.end(); ++it ) + { + root.setAttribute( QStringLiteral( "xmlns:" ) + it.key(), it.value() ); + } +} + QDomDocument QgsManageConnectionsDialog::saveOWSConnections( const QStringList &connections, const QString &service ) { QDomDocument doc( QStringLiteral( "connections" ) ); @@ -468,6 +476,7 @@ QDomDocument QgsManageConnectionsDialog::saveOWSConnections( const QStringList & root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) ); doc.appendChild( root ); + QMap namespaceDeclarations; for ( int i = 0; i < connections.count(); ++i ) { QDomElement el = doc.createElement( service.toLower() ); @@ -484,7 +493,7 @@ QDomDocument QgsManageConnectionsDialog::saveOWSConnections( const QStringList & el.setAttribute( QStringLiteral( "dpiMode" ), static_cast( QgsOwsConnection::settingsDpiMode->value( { service.toLower(), connections[i] } ) ) ); QgsHttpHeaders httpHeader( QgsOwsConnection::settingsHeaders->value( { service.toLower(), connections[i] } ) ); - httpHeader.updateDomElement( el ); + httpHeader.updateDomElement( el, namespaceDeclarations ); } el.setAttribute( QStringLiteral( "username" ), QgsOwsConnection::settingsUsername->value( { service.toLower(), connections[i] } ) ); @@ -492,6 +501,8 @@ QDomDocument QgsManageConnectionsDialog::saveOWSConnections( const QStringList & root.appendChild( el ); } + addNamespaceDeclarations( root, namespaceDeclarations ); + return doc; } @@ -710,6 +721,7 @@ QDomDocument QgsManageConnectionsDialog::saveXyzTilesConnections( const QStringL root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) ); doc.appendChild( root ); + QMap namespaceDeclarations; for ( int i = 0; i < connections.count(); ++i ) { QDomElement el = doc.createElement( QStringLiteral( "xyztiles" ) ); @@ -724,11 +736,13 @@ QDomDocument QgsManageConnectionsDialog::saveXyzTilesConnections( const QStringL el.setAttribute( QStringLiteral( "tilePixelRatio" ), QgsXyzConnectionSettings::settingsTilePixelRatio->value( connections[i] ) ); QgsHttpHeaders httpHeader( QgsXyzConnectionSettings::settingsHeaders->value( connections[i] ) ); - httpHeader.updateDomElement( el ); + httpHeader.updateDomElement( el, namespaceDeclarations ); root.appendChild( el ); } + addNamespaceDeclarations( root, namespaceDeclarations ); + return doc; } @@ -739,6 +753,7 @@ QDomDocument QgsManageConnectionsDialog::saveArcgisConnections( const QStringLis root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) ); doc.appendChild( root ); + QMap namespaceDeclarations; for ( const QString &connection : connections ) { QDomElement el = doc.createElement( QStringLiteral( "arcgisfeatureserver" ) ); @@ -746,7 +761,7 @@ QDomDocument QgsManageConnectionsDialog::saveArcgisConnections( const QStringLis el.setAttribute( QStringLiteral( "url" ), QgsArcGisConnectionSettings::settingsUrl->value( connection ) ); QgsHttpHeaders httpHeader( QgsArcGisConnectionSettings::settingsHeaders->value( connection ) ); - httpHeader.updateDomElement( el ); + httpHeader.updateDomElement( el, namespaceDeclarations ); el.setAttribute( QStringLiteral( "username" ), QgsArcGisConnectionSettings::settingsUsername->value( connection ) ); el.setAttribute( QStringLiteral( "password" ), QgsArcGisConnectionSettings::settingsPassword->value( connection ) ); @@ -755,6 +770,8 @@ QDomDocument QgsManageConnectionsDialog::saveArcgisConnections( const QStringLis root.appendChild( el ); } + addNamespaceDeclarations( root, namespaceDeclarations ); + return doc; } @@ -765,6 +782,7 @@ QDomDocument QgsManageConnectionsDialog::saveVectorTileConnections( const QStrin root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) ); doc.appendChild( root ); + QMap namespaceDeclarations; for ( int i = 0; i < connections.count(); ++i ) { QDomElement el = doc.createElement( QStringLiteral( "vectortile" ) ); @@ -780,11 +798,13 @@ QDomDocument QgsManageConnectionsDialog::saveVectorTileConnections( const QStrin el.setAttribute( QStringLiteral( "styleUrl" ), QgsVectorTileProviderConnection::settingsStyleUrl->value( connections[i] ) ); QgsHttpHeaders httpHeader( QgsVectorTileProviderConnection::settingsHeaders->value( connections[i] ) ); - httpHeader.updateDomElement( el ); + httpHeader.updateDomElement( el, namespaceDeclarations ); root.appendChild( el ); } + addNamespaceDeclarations( root, namespaceDeclarations ); + return doc; } @@ -795,6 +815,7 @@ QDomDocument QgsManageConnectionsDialog::saveTiledSceneConnections( const QStrin root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) ); doc.appendChild( root ); + QMap namespaceDeclarations; for ( int i = 0; i < connections.count(); ++i ) { QDomElement el = doc.createElement( QStringLiteral( "tiledscene" ) ); @@ -807,11 +828,13 @@ QDomDocument QgsManageConnectionsDialog::saveTiledSceneConnections( const QStrin el.setAttribute( QStringLiteral( "password" ), QgsTiledSceneProviderConnection::settingsPassword->value( connections[i] ) ); QgsHttpHeaders httpHeader( QgsTiledSceneProviderConnection::settingsHeaders->value( connections[i] ) ); - httpHeader.updateDomElement( el ); + httpHeader.updateDomElement( el, namespaceDeclarations ); root.appendChild( el ); } + addNamespaceDeclarations( root, namespaceDeclarations ); + return doc; } @@ -822,6 +845,7 @@ QDomDocument QgsManageConnectionsDialog::saveSensorThingsConnections( const QStr root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) ); doc.appendChild( root ); + QMap namespaceDeclarations; for ( int i = 0; i < connections.count(); ++i ) { QDomElement el = doc.createElement( QStringLiteral( "sensorthings" ) ); @@ -833,11 +857,13 @@ QDomDocument QgsManageConnectionsDialog::saveSensorThingsConnections( const QStr el.setAttribute( QStringLiteral( "password" ), QgsSensorThingsProviderConnection::settingsPassword->value( connections[i] ) ); QgsHttpHeaders httpHeader( QgsTiledSceneProviderConnection::settingsHeaders->value( connections[i] ) ); - httpHeader.updateDomElement( el ); + httpHeader.updateDomElement( el, namespaceDeclarations ); root.appendChild( el ); } + addNamespaceDeclarations( root, namespaceDeclarations ); + return doc; } @@ -882,6 +908,7 @@ QDomDocument QgsManageConnectionsDialog::saveStacConnections( const QStringList root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.0" ) ); doc.appendChild( root ); + QMap namespaceDeclarations; for ( int i = 0; i < connections.count(); ++i ) { QDomElement el = doc.createElement( QStringLiteral( "stac" ) ); @@ -893,11 +920,13 @@ QDomDocument QgsManageConnectionsDialog::saveStacConnections( const QStringList el.setAttribute( QStringLiteral( "password" ), QgsStacConnection::settingsPassword->value( connections[i] ) ); QgsHttpHeaders httpHeader( QgsStacConnection::settingsHeaders->value( connections[i] ) ); - httpHeader.updateDomElement( el ); + httpHeader.updateDomElement( el, namespaceDeclarations ); root.appendChild( el ); } + addNamespaceDeclarations( root, namespaceDeclarations ); + return doc; } diff --git a/tests/src/core/testqgshttpheaders.cpp b/tests/src/core/testqgshttpheaders.cpp index 9c2df3cc20ecb..a47fc9654e850 100644 --- a/tests/src/core/testqgshttpheaders.cpp +++ b/tests/src/core/testqgshttpheaders.cpp @@ -272,7 +272,8 @@ void TestQgsHttpheaders::updateSetDomElement() QDomElement element = doc.createElement( "qgs" ); // === update QgsHttpHeaders h( QVariantMap( { { QStringLiteral( "key1" ), "value1" }, { QgsHttpHeaders::KEY_REFERER, "my_ref" } } ) ); - h.updateDomElement( element ); + QMap namespaceDeclarations; + h.updateDomElement( element, namespaceDeclarations ); QVERIFY( element.hasAttribute( QgsHttpHeaders::PARAM_PREFIX + "key1" ) ); QCOMPARE( element.attribute( QgsHttpHeaders::PARAM_PREFIX + "key1" ), "value1" ); @@ -284,6 +285,8 @@ void TestQgsHttpheaders::updateSetDomElement() QVERIFY( element.hasAttribute( QgsHttpHeaders::KEY_REFERER ) ); QCOMPARE( element.attribute( QgsHttpHeaders::KEY_REFERER ), "my_ref" ); + QCOMPARE( namespaceDeclarations["http-header"], "https://qgis.org/http-header" ); + // === setFrom QgsHttpHeaders h2; element.setAttribute( QgsHttpHeaders::KEY_REFERER, "my_ref_root" ); // overwrite root ref to ckeck backward compatibility From c62e2d2096a79b25a0c403cccba866c29880b17a Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Fri, 24 Jan 2025 16:28:07 +0700 Subject: [PATCH 16/81] [ui][pythonm console] Fix hard to read python console editor icons --- .../default/console/iconClassBrowserConsole.svg | 11 ++++++++++- .../default/console/iconCommentEditorConsole.svg | 6 +++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/images/themes/default/console/iconClassBrowserConsole.svg b/images/themes/default/console/iconClassBrowserConsole.svg index 42bc5711d627b..031539ea9426e 100644 --- a/images/themes/default/console/iconClassBrowserConsole.svg +++ b/images/themes/default/console/iconClassBrowserConsole.svg @@ -1 +1,10 @@ - \ No newline at end of file + + + + + + + + + + diff --git a/images/themes/default/console/iconCommentEditorConsole.svg b/images/themes/default/console/iconCommentEditorConsole.svg index 6094e84fedfe2..36b445934a167 100644 --- a/images/themes/default/console/iconCommentEditorConsole.svg +++ b/images/themes/default/console/iconCommentEditorConsole.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + From 8f9024bcb6ad3c22d27167ccd72050c2cd6ae3fb Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Sun, 26 Jan 2025 17:41:49 +0700 Subject: [PATCH 17/81] Address review --- images/themes/default/console/iconCommentEditorConsole.svg | 3 +-- python/console/console.py | 7 +++++-- python/console/console_editor.py | 7 +++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/images/themes/default/console/iconCommentEditorConsole.svg b/images/themes/default/console/iconCommentEditorConsole.svg index 36b445934a167..44790de3166c4 100644 --- a/images/themes/default/console/iconCommentEditorConsole.svg +++ b/images/themes/default/console/iconCommentEditorConsole.svg @@ -1,5 +1,4 @@ - - + diff --git a/python/console/console.py b/python/console/console.py index ba15c4460f1ab..0789c2e312deb 100644 --- a/python/console/console.py +++ b/python/console/console.py @@ -46,7 +46,7 @@ QApplication, QShortcut, ) -from qgis.PyQt.QtGui import QDesktopServices, QKeySequence +from qgis.PyQt.QtGui import QDesktopServices, QKeySequence, QColor, QPalette from qgis.PyQt.QtWidgets import QVBoxLayout, QMessageBox from qgis.utils import iface from .console_sci import ShellScintilla @@ -320,7 +320,10 @@ def __init__(self, parent=None): self.toggleCommentEditorButton.setCheckable(False) self.toggleCommentEditorButton.setEnabled(True) self.toggleCommentEditorButton.setIcon( - QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg") + QgsApplication.getThemeIcon( + "console/iconCommentEditorConsole.svg", + self.palette().color(QPalette.WindowText), + ), ) self.toggleCommentEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole) self.toggleCommentEditorButton.setIconVisibleInMenu(True) diff --git a/python/console/console_editor.py b/python/console/console_editor.py index c7e868372c523..e18e93d6a31a2 100644 --- a/python/console/console_editor.py +++ b/python/console/console_editor.py @@ -48,7 +48,7 @@ Qt, QUrl, ) -from qgis.PyQt.QtGui import QKeySequence +from qgis.PyQt.QtGui import QKeySequence, QColor, QPalette from qgis.PyQt.QtNetwork import QNetworkRequest from qgis.PyQt.QtWidgets import ( QAction, @@ -261,7 +261,10 @@ def contextMenuEvent(self, e): menu.addSeparator() toggle_comment_action = QAction( - QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg"), + QgsApplication.getThemeIcon( + "console/iconCommentEditorConsole.svg", + self.palette().color(QPalette.WindowText), + ), QCoreApplication.translate("PythonConsole", "Toggle Comment"), menu, ) From efdb16ef3680c8b66bab7dd4b298097666651327 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Mon, 27 Jan 2025 09:56:31 +0700 Subject: [PATCH 18/81] Qt6 compatibility --- python/console/console.py | 2 +- python/console/console_editor.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/console/console.py b/python/console/console.py index 0789c2e312deb..3e495bc66ce39 100644 --- a/python/console/console.py +++ b/python/console/console.py @@ -322,7 +322,7 @@ def __init__(self, parent=None): self.toggleCommentEditorButton.setIcon( QgsApplication.getThemeIcon( "console/iconCommentEditorConsole.svg", - self.palette().color(QPalette.WindowText), + self.palette().color(QPalette.ColorRole.WindowText), ), ) self.toggleCommentEditorButton.setMenuRole(QAction.MenuRole.PreferencesRole) diff --git a/python/console/console_editor.py b/python/console/console_editor.py index e18e93d6a31a2..9503f6f92e2c4 100644 --- a/python/console/console_editor.py +++ b/python/console/console_editor.py @@ -263,7 +263,7 @@ def contextMenuEvent(self, e): toggle_comment_action = QAction( QgsApplication.getThemeIcon( "console/iconCommentEditorConsole.svg", - self.palette().color(QPalette.WindowText), + self.palette().color(QPalette.ColorRole.WindowText), ), QCoreApplication.translate("PythonConsole", "Toggle Comment"), menu, From b4b2dfdd21eb240a1d1f943333231488afc3eaee Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Wed, 29 Jan 2025 14:06:33 +0700 Subject: [PATCH 19/81] Address review --- python/plugins/processing/script/ScriptEditorDialog.py | 3 ++- src/gui/codeeditors/qgscodeeditor.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/python/plugins/processing/script/ScriptEditorDialog.py b/python/plugins/processing/script/ScriptEditorDialog.py index 373eb2c964cce..522387112f8f4 100644 --- a/python/plugins/processing/script/ScriptEditorDialog.py +++ b/python/plugins/processing/script/ScriptEditorDialog.py @@ -116,7 +116,8 @@ def clean_up_store(): QgsApplication.getThemeIcon("/mActionDecreaseFont.svg") ) self.actionToggleComment.setIcon( - QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg") + QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg"), + self.palette().color(QPalette.ColorRole.WindowText), ) # Connect signals and slots diff --git a/src/gui/codeeditors/qgscodeeditor.cpp b/src/gui/codeeditors/qgscodeeditor.cpp index 62128b6dd7be6..7a1df16d54506 100644 --- a/src/gui/codeeditors/qgscodeeditor.cpp +++ b/src/gui/codeeditors/qgscodeeditor.cpp @@ -318,7 +318,7 @@ void QgsCodeEditor::contextMenuEvent( QContextMenuEvent *event ) { QAction *toggleCommentAction = new QAction( tr( "Toggle Comment" ), menu ); toggleCommentAction->setShortcut( QStringLiteral( "Ctrl+:" ) ); - toggleCommentAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconCommentEditorConsole.svg" ) ) ); + toggleCommentAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconCommentEditorConsole.svg" ), palette().color( QPalette::ColorRole::WindowText ) ) ); toggleCommentAction->setEnabled( !isReadOnly() ); connect( toggleCommentAction, &QAction::triggered, this, &QgsCodeEditor::toggleComment ); menu->addAction( toggleCommentAction ); From 964ef3a735bb9a4d2f34826295233eee358cdff0 Mon Sep 17 00:00:00 2001 From: qgis-bot Date: Wed, 29 Jan 2025 22:50:24 +0000 Subject: [PATCH 20/81] =?UTF-8?q?auto=20sipify=20=F0=9F=8D=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/PyQt6/core/class_map.yaml | 16 ++++++++-------- python/core/class_map.yaml | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/python/PyQt6/core/class_map.yaml b/python/PyQt6/core/class_map.yaml index 113d085d6dba6..2cfd1f2cea72b 100644 --- a/python/PyQt6/core/class_map.yaml +++ b/python/PyQt6/core/class_map.yaml @@ -5816,14 +5816,14 @@ QgsHtmlAnnotation: src/core/annotations/qgshtmlannotation.h#L34 QgsHtmlUtils.buildBulletList: src/core/qgshtmlutils.h#L38 QgsHtmlUtils: src/core/qgshtmlutils.h#L30 QgsHttpHeaders.headers: src/core/network/qgshttpheaders.h#L93 -QgsHttpHeaders.insert: src/core/network/qgshttpheaders.h#L190 -QgsHttpHeaders.sanitizeKey: src/core/network/qgshttpheaders.h#L175 -QgsHttpHeaders.setFromDomElement: src/core/network/qgshttpheaders.h#L169 -QgsHttpHeaders.setFromMap: src/core/network/qgshttpheaders.h#L160 -QgsHttpHeaders.setFromSettings: src/core/network/qgshttpheaders.h#L145 -QgsHttpHeaders.setFromUrlQuery: src/core/network/qgshttpheaders.h#L151 -QgsHttpHeaders.toSpacedString: src/core/network/qgshttpheaders.h#L198 -QgsHttpHeaders.updateDomElement: src/core/network/qgshttpheaders.h#L135 +QgsHttpHeaders.insert: src/core/network/qgshttpheaders.h#L203 +QgsHttpHeaders.sanitizeKey: src/core/network/qgshttpheaders.h#L188 +QgsHttpHeaders.setFromDomElement: src/core/network/qgshttpheaders.h#L182 +QgsHttpHeaders.setFromMap: src/core/network/qgshttpheaders.h#L173 +QgsHttpHeaders.setFromSettings: src/core/network/qgshttpheaders.h#L158 +QgsHttpHeaders.setFromUrlQuery: src/core/network/qgshttpheaders.h#L164 +QgsHttpHeaders.toSpacedString: src/core/network/qgshttpheaders.h#L211 +QgsHttpHeaders.updateDomElement: src/core/network/qgshttpheaders.h#L137 QgsHttpHeaders.updateMap: src/core/network/qgshttpheaders.h#L126 QgsHttpHeaders.updateNetworkRequest: src/core/network/qgshttpheaders.h#L111 QgsHttpHeaders.updateSettings: src/core/network/qgshttpheaders.h#L105 diff --git a/python/core/class_map.yaml b/python/core/class_map.yaml index a2c2ba8e80b29..29cd8097247e0 100644 --- a/python/core/class_map.yaml +++ b/python/core/class_map.yaml @@ -5816,14 +5816,14 @@ QgsHtmlAnnotation: src/core/annotations/qgshtmlannotation.h#L34 QgsHtmlUtils.buildBulletList: src/core/qgshtmlutils.h#L38 QgsHtmlUtils: src/core/qgshtmlutils.h#L30 QgsHttpHeaders.headers: src/core/network/qgshttpheaders.h#L93 -QgsHttpHeaders.insert: src/core/network/qgshttpheaders.h#L190 -QgsHttpHeaders.sanitizeKey: src/core/network/qgshttpheaders.h#L175 -QgsHttpHeaders.setFromDomElement: src/core/network/qgshttpheaders.h#L169 -QgsHttpHeaders.setFromMap: src/core/network/qgshttpheaders.h#L160 -QgsHttpHeaders.setFromSettings: src/core/network/qgshttpheaders.h#L145 -QgsHttpHeaders.setFromUrlQuery: src/core/network/qgshttpheaders.h#L151 -QgsHttpHeaders.toSpacedString: src/core/network/qgshttpheaders.h#L198 -QgsHttpHeaders.updateDomElement: src/core/network/qgshttpheaders.h#L135 +QgsHttpHeaders.insert: src/core/network/qgshttpheaders.h#L203 +QgsHttpHeaders.sanitizeKey: src/core/network/qgshttpheaders.h#L188 +QgsHttpHeaders.setFromDomElement: src/core/network/qgshttpheaders.h#L182 +QgsHttpHeaders.setFromMap: src/core/network/qgshttpheaders.h#L173 +QgsHttpHeaders.setFromSettings: src/core/network/qgshttpheaders.h#L158 +QgsHttpHeaders.setFromUrlQuery: src/core/network/qgshttpheaders.h#L164 +QgsHttpHeaders.toSpacedString: src/core/network/qgshttpheaders.h#L211 +QgsHttpHeaders.updateDomElement: src/core/network/qgshttpheaders.h#L137 QgsHttpHeaders.updateMap: src/core/network/qgshttpheaders.h#L126 QgsHttpHeaders.updateNetworkRequest: src/core/network/qgshttpheaders.h#L111 QgsHttpHeaders.updateSettings: src/core/network/qgshttpheaders.h#L105 From a0414c4883657d62b0738d7d9a29285d98cc7d78 Mon Sep 17 00:00:00 2001 From: Martin Dobias Date: Wed, 29 Jan 2025 16:25:20 +0100 Subject: [PATCH 21/81] QgsChunkBoundsEntity: use 3D boxes in map coordinates + QgsGeoTransform Until now, chunk bounds entity used axis-aligned bboxes in world coordinates (floats) We are switching to bboxes in map coordinates (doubles) and we use QgsGeoTransform to react correctly when the origin vector changes. --- .../auto_generated/geometry/qgsbox3d.sip.in | 14 +++++++++- .../auto_generated/geometry/qgsbox3d.sip.in | 14 +++++++++- src/3d/chunks/qgschunkboundsentity_p.cpp | 18 ++++++++++-- src/3d/chunks/qgschunkboundsentity_p.h | 12 ++++++-- src/3d/chunks/qgschunkedentity.cpp | 6 ++-- src/3d/qgsaabb.h | 17 +++++++++++ src/3d/qgsvirtualpointcloudentity_p.cpp | 28 +++++++++---------- src/3d/qgsvirtualpointcloudentity_p.h | 5 +--- src/core/geometry/qgsbox3d.cpp | 2 +- src/core/geometry/qgsbox3d.h | 11 +++++++- tests/src/3d/testqgs3dutils.cpp | 8 +++--- 11 files changed, 100 insertions(+), 35 deletions(-) diff --git a/python/PyQt6/core/auto_generated/geometry/qgsbox3d.sip.in b/python/PyQt6/core/auto_generated/geometry/qgsbox3d.sip.in index c3205eeb8b43b..0aac4b55e7bf3 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgsbox3d.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgsbox3d.sip.in @@ -375,12 +375,24 @@ Expands the bbox so that it covers both the original rectangle and the given poi Converts the box to a 2D rectangle. %End - double distanceTo( const QVector3D &point ) const /HoldGIL/; + double distanceTo( const QVector3D &point ) const /Deprecated="Since 3.42. Use distanceTo() with QgsVector3D instead (QVector3D uses floats)."/; %Docstring Returns the smallest distance between the box and the point ``point`` (returns 0 if the point is inside the box) .. versionadded:: 3.18 + +.. deprecated:: 3.42 + + Use :py:func:`~QgsBox3D.distanceTo` with :py:class:`QgsVector3D` instead (QVector3D uses floats). +%End + + double distanceTo( const QgsVector3D &point ) const /HoldGIL/; +%Docstring +Returns the smallest distance between the box and the point ``point`` +(returns 0 if the point is inside the box) + +.. versionadded:: 3.42 %End bool operator==( const QgsBox3D &other ) const /HoldGIL/; diff --git a/python/core/auto_generated/geometry/qgsbox3d.sip.in b/python/core/auto_generated/geometry/qgsbox3d.sip.in index c3205eeb8b43b..0aac4b55e7bf3 100644 --- a/python/core/auto_generated/geometry/qgsbox3d.sip.in +++ b/python/core/auto_generated/geometry/qgsbox3d.sip.in @@ -375,12 +375,24 @@ Expands the bbox so that it covers both the original rectangle and the given poi Converts the box to a 2D rectangle. %End - double distanceTo( const QVector3D &point ) const /HoldGIL/; + double distanceTo( const QVector3D &point ) const /Deprecated="Since 3.42. Use distanceTo() with QgsVector3D instead (QVector3D uses floats)."/; %Docstring Returns the smallest distance between the box and the point ``point`` (returns 0 if the point is inside the box) .. versionadded:: 3.18 + +.. deprecated:: 3.42 + + Use :py:func:`~QgsBox3D.distanceTo` with :py:class:`QgsVector3D` instead (QVector3D uses floats). +%End + + double distanceTo( const QgsVector3D &point ) const /HoldGIL/; +%Docstring +Returns the smallest distance between the box and the point ``point`` +(returns 0 if the point is inside the box) + +.. versionadded:: 3.42 %End bool operator==( const QgsBox3D &other ) const /HoldGIL/; diff --git a/src/3d/chunks/qgschunkboundsentity_p.cpp b/src/3d/chunks/qgschunkboundsentity_p.cpp index b9a2ed9b1154e..a73782c2ab6aa 100644 --- a/src/3d/chunks/qgschunkboundsentity_p.cpp +++ b/src/3d/chunks/qgschunkboundsentity_p.cpp @@ -20,12 +20,15 @@ #include "qgsaabb.h" #include "qgs3dwiredmesh_p.h" +#include "qgsbox3d.h" +#include "qgsgeotransform.h" ///@cond PRIVATE -QgsChunkBoundsEntity::QgsChunkBoundsEntity( Qt3DCore::QNode *parent ) +QgsChunkBoundsEntity::QgsChunkBoundsEntity( const QgsVector3D &vertexDataOrigin, Qt3DCore::QNode *parent ) : Qt3DCore::QEntity( parent ) + , mVertexDataOrigin( vertexDataOrigin ) { mAabbMesh = new Qgs3DWiredMesh; addComponent( mAabbMesh ); @@ -33,11 +36,20 @@ QgsChunkBoundsEntity::QgsChunkBoundsEntity( Qt3DCore::QNode *parent ) Qt3DExtras::QPhongMaterial *bboxesMaterial = new Qt3DExtras::QPhongMaterial; bboxesMaterial->setAmbient( Qt::red ); addComponent( bboxesMaterial ); + + QgsGeoTransform *transform = new QgsGeoTransform; + transform->setGeoTranslation( mVertexDataOrigin ); + addComponent( transform ); } -void QgsChunkBoundsEntity::setBoxes( const QList &bboxes ) +void QgsChunkBoundsEntity::setBoxes( const QList &bboxes ) { - mAabbMesh->setVertices( bboxes ); + QList aabbBoxes; + for ( const QgsBox3D &box : bboxes ) + { + aabbBoxes << QgsAABB::fromBox3D( box, mVertexDataOrigin ); + } + mAabbMesh->setVertices( aabbBoxes ); } /// @endcond diff --git a/src/3d/chunks/qgschunkboundsentity_p.h b/src/3d/chunks/qgschunkboundsentity_p.h index 5e3ff8c4ecf34..c7450a6cf15d0 100644 --- a/src/3d/chunks/qgschunkboundsentity_p.h +++ b/src/3d/chunks/qgschunkboundsentity_p.h @@ -29,7 +29,9 @@ #include -class QgsAABB; +#include "qgsvector3d.h" + +class QgsBox3D; class Qgs3DWiredMesh; #define SIP_NO_FILE @@ -46,12 +48,16 @@ class QgsChunkBoundsEntity : public Qt3DCore::QEntity public: //! Constructs the entity - QgsChunkBoundsEntity( Qt3DCore::QNode *parent = nullptr ); + QgsChunkBoundsEntity( const QgsVector3D &vertexDataOrigin, Qt3DCore::QNode *parent = nullptr ); //! Sets a list of bounding boxes to be rendered by the entity - void setBoxes( const QList &bboxes ); + void setBoxes( const QList &bboxes ); + + //! Returns origin of vertex data used in this entity + QgsVector3D vertexDataOrigin() const { return mVertexDataOrigin; } private: + QgsVector3D mVertexDataOrigin; Qgs3DWiredMesh *mAabbMesh = nullptr; }; diff --git a/src/3d/chunks/qgschunkedentity.cpp b/src/3d/chunks/qgschunkedentity.cpp index ad05bfb0ae0cb..b189b93cb6301 100644 --- a/src/3d/chunks/qgschunkedentity.cpp +++ b/src/3d/chunks/qgschunkedentity.cpp @@ -201,9 +201,9 @@ void QgsChunkedEntity::handleSceneUpdate( const SceneContext &sceneContext ) if ( mBboxesEntity ) { - QList bboxes; + QList bboxes; for ( QgsChunkNode *n : std::as_const( mActiveNodes ) ) - bboxes << Qgs3DUtils::mapToWorldExtent( n->box3D(), mMapSettings->origin() ); + bboxes << n->box3D(); mBboxesEntity->setBoxes( bboxes ); } @@ -301,7 +301,7 @@ void QgsChunkedEntity::setShowBoundingBoxes( bool enabled ) if ( enabled ) { - mBboxesEntity = new QgsChunkBoundsEntity( this ); + mBboxesEntity = new QgsChunkBoundsEntity( mRootNode->box3D().center(), this ); } else { diff --git a/src/3d/qgsaabb.h b/src/3d/qgsaabb.h index f63e2f3d6eb7c..406388881b436 100644 --- a/src/3d/qgsaabb.h +++ b/src/3d/qgsaabb.h @@ -22,6 +22,8 @@ #include #include +#include "qgsbox3d.h" + #define SIP_NO_FILE /** @@ -38,6 +40,21 @@ class _3D_EXPORT QgsAABB //! Constructs bounding box QgsAABB( float xMin, float yMin, float zMin, float xMax, float yMax, float zMax ); + /** + * Constructs bounding box from QgsBox3D by subtracting origin 3D vector. + * Note: this is potentially lossy operation as the coordinates are converted + * from double values to floats! + */ + static QgsAABB fromBox3D( const QgsBox3D &box3D, const QgsVector3D &origin ) + { + return QgsAABB( static_cast( box3D.xMinimum() - origin.x() ), + static_cast( box3D.yMinimum() - origin.y() ), + static_cast( box3D.zMinimum() - origin.z() ), + static_cast( box3D.xMaximum() - origin.x() ), + static_cast( box3D.yMaximum() - origin.y() ), + static_cast( box3D.zMaximum() - origin.z() ) ); + } + //! Returns box width in X axis float xExtent() const { return xMax - xMin; } //! Returns box width in Y axis diff --git a/src/3d/qgsvirtualpointcloudentity_p.cpp b/src/3d/qgsvirtualpointcloudentity_p.cpp index 44f58f90f69ac..f8936ada1706d 100644 --- a/src/3d/qgsvirtualpointcloudentity_p.cpp +++ b/src/3d/qgsvirtualpointcloudentity_p.cpp @@ -44,7 +44,6 @@ QgsVirtualPointCloudEntity::QgsVirtualPointCloudEntity( , mShowBoundingBoxes( showBoundingBoxes ) { mSymbol.reset( symbol ); - mBboxesEntity = new QgsChunkBoundsEntity( this ); const QgsRectangle mapExtent = Qgs3DUtils::tryReprojectExtent2D( map->extent(), map->crs(), layer->crs(), map->transformContext() ); const QVector subIndexes = provider()->subIndexes(); for ( int i = 0; i < subIndexes.size(); ++i ) @@ -52,7 +51,7 @@ QgsVirtualPointCloudEntity::QgsVirtualPointCloudEntity( const QgsPointCloudSubIndex &si = subIndexes.at( i ); const QgsRectangle intersection = si.extent().intersect( mapExtent ); - mBboxes << Qgs3DUtils::mapToWorldExtent( intersection, si.zRange().lower(), si.zRange().upper(), map->origin() ); + mBboxes << QgsBox3D( intersection, si.zRange().lower(), si.zRange().upper() ); createChunkedEntityForSubIndex( i ); } @@ -76,6 +75,10 @@ QgsVirtualPointCloudEntity::QgsVirtualPointCloudEntity( emit newEntityCreated( mOverviewEntity ); } + // this is a rather arbitrary point, it could be somewhere else, ideally near the actual data + QgsVector3D boundsEntityOrigin( mapExtent.center().x(), mapExtent.center().y(), 0 ); + + mBboxesEntity = new QgsChunkBoundsEntity( boundsEntityOrigin, this ); updateBboxEntity(); connect( this, &QgsVirtualPointCloudEntity::subIndexNeedsLoading, provider(), &QgsVirtualPointCloudProvider::loadSubIndex, Qt::QueuedConnection ); connect( provider(), &QgsVirtualPointCloudProvider::subIndexLoaded, this, &QgsVirtualPointCloudEntity::createChunkedEntityForSubIndex ); @@ -91,11 +94,6 @@ QgsVirtualPointCloudProvider *QgsVirtualPointCloudEntity::provider() const return qobject_cast( mLayer->dataProvider() ); } -QgsAABB QgsVirtualPointCloudEntity::boundingBox( int i ) const -{ - return mBboxes.at( i ); -} - void QgsVirtualPointCloudEntity::createChunkedEntityForSubIndex( int i ) { const QVector subIndexes = provider()->subIndexes(); @@ -126,18 +124,19 @@ void QgsVirtualPointCloudEntity::createChunkedEntityForSubIndex( int i ) void QgsVirtualPointCloudEntity::handleSceneUpdate( const SceneContext &sceneContext ) { + QgsVector3D cameraPosMapCoords = QgsVector3D( sceneContext.cameraPos ) + mapSettings()->origin(); const QVector subIndexes = provider()->subIndexes(); for ( int i = 0; i < subIndexes.size(); ++i ) { - const QgsAABB &bbox = mBboxes.at( i ); + const QgsBox3D &box3D = mBboxes.at( i ); - if ( bbox.isEmpty() ) + if ( box3D.isEmpty() ) continue; // magic number 256 is the common span value for a COPC root node constexpr int SPAN = 256; - const float epsilon = std::min( bbox.xExtent(), bbox.yExtent() ) / SPAN; - const float distance = bbox.distanceFromPoint( sceneContext.cameraPos ); + const float epsilon = std::min( box3D.width(), box3D.height() ) / SPAN; + const float distance = box3D.distanceTo( cameraPosMapCoords ); const float sse = Qgs3DUtils::screenSpaceError( epsilon, distance, sceneContext.screenSizePx, sceneContext.cameraFov ); constexpr float THRESHOLD = .2; @@ -178,11 +177,12 @@ QgsRange QgsVirtualPointCloudEntity::getNearFarPlaneRange( const QMatrix4 // if there were no chunked entities available, we will iterate the bboxes as a fallback instead if ( fnear == 1e9 && ffar == 0 ) { - for ( const QgsAABB &bbox : mBboxes ) + for ( const QgsBox3D &box : mBboxes ) { + QgsAABB aabb = QgsAABB::fromBox3D( box, mBboxesEntity->vertexDataOrigin() ); float bboxfnear; float bboxffar; - Qgs3DUtils::computeBoundingBoxNearFarPlanes( bbox, viewMatrix, bboxfnear, bboxffar ); + Qgs3DUtils::computeBoundingBoxNearFarPlanes( aabb, viewMatrix, bboxfnear, bboxffar ); fnear = std::min( fnear, bboxfnear ); ffar = std::max( ffar, bboxffar ); } @@ -214,7 +214,7 @@ bool QgsVirtualPointCloudEntity::needsUpdate() const void QgsVirtualPointCloudEntity::updateBboxEntity() { - QList bboxes; + QList bboxes; // we want to render bounding boxes only when zoomOutBehavior is RenderExtents or RenderOverviewAndExtents const QgsPointCloudLayer3DRenderer *renderer = dynamic_cast( mLayer->renderer3D() ); if ( renderer && renderer->zoomOutBehavior() != Qgis::PointCloudZoomOutRenderBehavior::RenderOverview ) diff --git a/src/3d/qgsvirtualpointcloudentity_p.h b/src/3d/qgsvirtualpointcloudentity_p.h index ed9b08904da7c..4b03cb32007b8 100644 --- a/src/3d/qgsvirtualpointcloudentity_p.h +++ b/src/3d/qgsvirtualpointcloudentity_p.h @@ -88,14 +88,11 @@ class QgsVirtualPointCloudEntity : public Qgs3DMapSceneEntity //! Returns a pointer to the associated layer's provider QgsVirtualPointCloudProvider *provider() const; - //! Returns the bounding box for sub index i - QgsAABB boundingBox( int i ) const; - QgsPointCloudLayer *mLayer = nullptr; QMap mChunkedEntitiesMap; QgsChunkBoundsEntity *mBboxesEntity = nullptr; QgsPointCloudLayerChunkedEntity *mOverviewEntity = nullptr; - QList mBboxes; + QList mBboxes; QgsCoordinateTransform mCoordinateTransform; std::unique_ptr mSymbol; double mZValueScale = 1.0; diff --git a/src/core/geometry/qgsbox3d.cpp b/src/core/geometry/qgsbox3d.cpp index dc6b7d4c3dcb6..802491b02b5ff 100644 --- a/src/core/geometry/qgsbox3d.cpp +++ b/src/core/geometry/qgsbox3d.cpp @@ -245,7 +245,7 @@ void QgsBox3D::combineWith( double x, double y, double z ) } } -double QgsBox3D::distanceTo( const QVector3D &point ) const +double QgsBox3D::distanceTo( const QgsVector3D &point ) const { const double dx = std::max( mBounds2d.xMinimum() - point.x(), std::max( 0., point.x() - mBounds2d.xMaximum() ) ); const double dy = std::max( mBounds2d.yMinimum() - point.y(), std::max( 0., point.y() - mBounds2d.yMaximum() ) ); diff --git a/src/core/geometry/qgsbox3d.h b/src/core/geometry/qgsbox3d.h index 72dd81ae0052c..ba181de58c35d 100644 --- a/src/core/geometry/qgsbox3d.h +++ b/src/core/geometry/qgsbox3d.h @@ -398,8 +398,17 @@ class CORE_EXPORT QgsBox3D * (returns 0 if the point is inside the box) * * \since QGIS 3.18 + * \deprecated QGIS 3.42. Use distanceTo() with QgsVector3D instead (QVector3D uses floats). */ - double distanceTo( const QVector3D &point ) const SIP_HOLDGIL; + double distanceTo( const QVector3D &point ) const SIP_DEPRECATED { return distanceTo( QgsVector3D( point ) ); } + + /** + * Returns the smallest distance between the box and the point \a point + * (returns 0 if the point is inside the box) + * + * \since QGIS 3.42 + */ + double distanceTo( const QgsVector3D &point ) const SIP_HOLDGIL; bool operator==( const QgsBox3D &other ) const SIP_HOLDGIL; diff --git a/tests/src/3d/testqgs3dutils.cpp b/tests/src/3d/testqgs3dutils.cpp index 6cc4f3e2401c0..30e1afe4f96e4 100644 --- a/tests/src/3d/testqgs3dutils.cpp +++ b/tests/src/3d/testqgs3dutils.cpp @@ -175,13 +175,13 @@ void TestQgs3DUtils::testQgsBox3DDistanceTo() { { const QgsBox3D box( -1, -1, -1, 1, 1, 1 ); - QCOMPARE( box.distanceTo( QVector3D( 0, 0, 0 ) ), 0.0 ); - QCOMPARE( box.distanceTo( QVector3D( 2, 2, 2 ) ), qSqrt( 3.0 ) ); + QCOMPARE( box.distanceTo( QgsVector3D( 0, 0, 0 ) ), 0.0 ); + QCOMPARE( box.distanceTo( QgsVector3D( 2, 2, 2 ) ), qSqrt( 3.0 ) ); } { const QgsBox3D box( 1, 2, 1, 4, 3, 3 ); - QCOMPARE( box.distanceTo( QVector3D( 1, 2, 1 ) ), 0.0 ); - QCOMPARE( box.distanceTo( QVector3D( 0, 0, 0 ) ), qSqrt( 6.0 ) ); + QCOMPARE( box.distanceTo( QgsVector3D( 1, 2, 1 ) ), 0.0 ); + QCOMPARE( box.distanceTo( QgsVector3D( 0, 0, 0 ) ), qSqrt( 6.0 ) ); } } From 5905092ce6bb09c0f10f0fcbf2d9448cc3318e90 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 29 Jan 2025 15:28:33 +0000 Subject: [PATCH 22/81] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/3d/qgsaabb.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/3d/qgsaabb.h b/src/3d/qgsaabb.h index 406388881b436..d7bf72b4cd434 100644 --- a/src/3d/qgsaabb.h +++ b/src/3d/qgsaabb.h @@ -47,12 +47,7 @@ class _3D_EXPORT QgsAABB */ static QgsAABB fromBox3D( const QgsBox3D &box3D, const QgsVector3D &origin ) { - return QgsAABB( static_cast( box3D.xMinimum() - origin.x() ), - static_cast( box3D.yMinimum() - origin.y() ), - static_cast( box3D.zMinimum() - origin.z() ), - static_cast( box3D.xMaximum() - origin.x() ), - static_cast( box3D.yMaximum() - origin.y() ), - static_cast( box3D.zMaximum() - origin.z() ) ); + return QgsAABB( static_cast( box3D.xMinimum() - origin.x() ), static_cast( box3D.yMinimum() - origin.y() ), static_cast( box3D.zMinimum() - origin.z() ), static_cast( box3D.xMaximum() - origin.x() ), static_cast( box3D.yMaximum() - origin.y() ), static_cast( box3D.zMaximum() - origin.z() ) ); } //! Returns box width in X axis From 85114263042651243bda1aa120e4f60092999165 Mon Sep 17 00:00:00 2001 From: Martin Dobias Date: Wed, 29 Jan 2025 21:25:51 +0100 Subject: [PATCH 23/81] doc and clang tidy fixes --- python/PyQt6/core/auto_generated/geometry/qgsbox3d.sip.in | 2 +- python/core/auto_generated/geometry/qgsbox3d.sip.in | 2 +- src/3d/qgsvirtualpointcloudentity_p.cpp | 4 ++-- src/core/geometry/qgsbox3d.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/PyQt6/core/auto_generated/geometry/qgsbox3d.sip.in b/python/PyQt6/core/auto_generated/geometry/qgsbox3d.sip.in index 0aac4b55e7bf3..18edcd44c9c2a 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgsbox3d.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgsbox3d.sip.in @@ -375,7 +375,7 @@ Expands the bbox so that it covers both the original rectangle and the given poi Converts the box to a 2D rectangle. %End - double distanceTo( const QVector3D &point ) const /Deprecated="Since 3.42. Use distanceTo() with QgsVector3D instead (QVector3D uses floats)."/; + double distanceTo( const QVector3D &point ) const /Deprecated="Since 3.42. Use distanceTo() with QgsVector3D instead (QVector3D uses floats)."/; %Docstring Returns the smallest distance between the box and the point ``point`` (returns 0 if the point is inside the box) diff --git a/python/core/auto_generated/geometry/qgsbox3d.sip.in b/python/core/auto_generated/geometry/qgsbox3d.sip.in index 0aac4b55e7bf3..18edcd44c9c2a 100644 --- a/python/core/auto_generated/geometry/qgsbox3d.sip.in +++ b/python/core/auto_generated/geometry/qgsbox3d.sip.in @@ -375,7 +375,7 @@ Expands the bbox so that it covers both the original rectangle and the given poi Converts the box to a 2D rectangle. %End - double distanceTo( const QVector3D &point ) const /Deprecated="Since 3.42. Use distanceTo() with QgsVector3D instead (QVector3D uses floats)."/; + double distanceTo( const QVector3D &point ) const /Deprecated="Since 3.42. Use distanceTo() with QgsVector3D instead (QVector3D uses floats)."/; %Docstring Returns the smallest distance between the box and the point ``point`` (returns 0 if the point is inside the box) diff --git a/src/3d/qgsvirtualpointcloudentity_p.cpp b/src/3d/qgsvirtualpointcloudentity_p.cpp index f8936ada1706d..78bf4f8ad3b60 100644 --- a/src/3d/qgsvirtualpointcloudentity_p.cpp +++ b/src/3d/qgsvirtualpointcloudentity_p.cpp @@ -135,8 +135,8 @@ void QgsVirtualPointCloudEntity::handleSceneUpdate( const SceneContext &sceneCon // magic number 256 is the common span value for a COPC root node constexpr int SPAN = 256; - const float epsilon = std::min( box3D.width(), box3D.height() ) / SPAN; - const float distance = box3D.distanceTo( cameraPosMapCoords ); + const float epsilon = static_cast( std::min( box3D.width(), box3D.height() ) ) / SPAN; + const float distance = static_cast( box3D.distanceTo( cameraPosMapCoords ) ); const float sse = Qgs3DUtils::screenSpaceError( epsilon, distance, sceneContext.screenSizePx, sceneContext.cameraFov ); constexpr float THRESHOLD = .2; diff --git a/src/core/geometry/qgsbox3d.h b/src/core/geometry/qgsbox3d.h index ba181de58c35d..d4d1d7777bc15 100644 --- a/src/core/geometry/qgsbox3d.h +++ b/src/core/geometry/qgsbox3d.h @@ -400,7 +400,7 @@ class CORE_EXPORT QgsBox3D * \since QGIS 3.18 * \deprecated QGIS 3.42. Use distanceTo() with QgsVector3D instead (QVector3D uses floats). */ - double distanceTo( const QVector3D &point ) const SIP_DEPRECATED { return distanceTo( QgsVector3D( point ) ); } + Q_DECL_DEPRECATED double distanceTo( const QVector3D &point ) const SIP_DEPRECATED { return distanceTo( QgsVector3D( point ) ); } /** * Returns the smallest distance between the box and the point \a point From 02719c5939c517de9ec6e3ceeb3d884c025e16b5 Mon Sep 17 00:00:00 2001 From: qgis-bot Date: Wed, 29 Jan 2025 23:34:28 +0000 Subject: [PATCH 24/81] =?UTF-8?q?auto=20sipify=20=F0=9F=8D=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/PyQt6/core/class_map.yaml | 17 +++++++++-------- python/core/class_map.yaml | 17 +++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/python/PyQt6/core/class_map.yaml b/python/PyQt6/core/class_map.yaml index 2cfd1f2cea72b..f318f486f282d 100644 --- a/python/PyQt6/core/class_map.yaml +++ b/python/PyQt6/core/class_map.yaml @@ -1844,7 +1844,7 @@ QgsBookmarkManagerModel.rowCount: src/core/qgsbookmarkmodel.h#L87 QgsBookmarkManagerModel.setData: src/core/qgsbookmarkmodel.h#L91 QgsBookmarkManagerModel: src/core/qgsbookmarkmodel.h#L41 QgsBookmarkManagerProxyModel: src/core/qgsbookmarkmodel.h#L119 -QgsBox3D.__repr__: src/core/geometry/qgsbox3d.h#L489 +QgsBox3D.__repr__: src/core/geometry/qgsbox3d.h#L498 QgsBox3D.area: src/core/geometry/qgsbox3d.h#L321 QgsBox3D.center: src/core/geometry/qgsbox3d.h#L314 QgsBox3D.combineWith: src/core/geometry/qgsbox3d.h#L382 @@ -1853,18 +1853,19 @@ QgsBox3D.contains: src/core/geometry/qgsbox3d.h#L356 QgsBox3D.contains: src/core/geometry/qgsbox3d.h#L364 QgsBox3D.contains: src/core/geometry/qgsbox3d.h#L375 QgsBox3D.depth: src/core/geometry/qgsbox3d.h#L307 -QgsBox3D.distanceTo: src/core/geometry/qgsbox3d.h#L402 -QgsBox3D.grow: src/core/geometry/qgsbox3d.h#L426 +QgsBox3D.distanceTo: src/core/geometry/qgsbox3d.h#L403 +QgsBox3D.distanceTo: src/core/geometry/qgsbox3d.h#L411 +QgsBox3D.grow: src/core/geometry/qgsbox3d.h#L435 QgsBox3D.height: src/core/geometry/qgsbox3d.h#L300 QgsBox3D.intersect: src/core/geometry/qgsbox3d.h#L331 QgsBox3D.intersects: src/core/geometry/qgsbox3d.h#L351 QgsBox3D.is2d: src/core/geometry/qgsbox3d.h#L337 QgsBox3D.is3D: src/core/geometry/qgsbox3d.h#L346 -QgsBox3D.isEmpty: src/core/geometry/qgsbox3d.h#L447 -QgsBox3D.isNull: src/core/geometry/qgsbox3d.h#L437 +QgsBox3D.isEmpty: src/core/geometry/qgsbox3d.h#L456 +QgsBox3D.isNull: src/core/geometry/qgsbox3d.h#L446 QgsBox3D.normalize: src/core/geometry/qgsbox3d.h#L286 -QgsBox3D.scale: src/core/geometry/qgsbox3d.h#L413 -QgsBox3D.scale: src/core/geometry/qgsbox3d.h#L420 +QgsBox3D.scale: src/core/geometry/qgsbox3d.h#L422 +QgsBox3D.scale: src/core/geometry/qgsbox3d.h#L429 QgsBox3D.set: src/core/geometry/qgsbox3d.h#L190 QgsBox3D.setNull: src/core/geometry/qgsbox3d.h#L281 QgsBox3D.setXMaximum: src/core/geometry/qgsbox3d.h#L204 @@ -1874,7 +1875,7 @@ QgsBox3D.setYMinimum: src/core/geometry/qgsbox3d.h#L225 QgsBox3D.setZMaximum: src/core/geometry/qgsbox3d.h#L260 QgsBox3D.setZMinimum: src/core/geometry/qgsbox3d.h#L253 QgsBox3D.toRectangle: src/core/geometry/qgsbox3d.h#L394 -QgsBox3D.toString: src/core/geometry/qgsbox3d.h#L456 +QgsBox3D.toString: src/core/geometry/qgsbox3d.h#L465 QgsBox3D.volume: src/core/geometry/qgsbox3d.h#L326 QgsBox3D.width: src/core/geometry/qgsbox3d.h#L293 QgsBox3D.xMaximum: src/core/geometry/qgsbox3d.h#L218 diff --git a/python/core/class_map.yaml b/python/core/class_map.yaml index 29cd8097247e0..47d7d71081b87 100644 --- a/python/core/class_map.yaml +++ b/python/core/class_map.yaml @@ -1844,7 +1844,7 @@ QgsBookmarkManagerModel.rowCount: src/core/qgsbookmarkmodel.h#L87 QgsBookmarkManagerModel.setData: src/core/qgsbookmarkmodel.h#L91 QgsBookmarkManagerModel: src/core/qgsbookmarkmodel.h#L41 QgsBookmarkManagerProxyModel: src/core/qgsbookmarkmodel.h#L119 -QgsBox3D.__repr__: src/core/geometry/qgsbox3d.h#L489 +QgsBox3D.__repr__: src/core/geometry/qgsbox3d.h#L498 QgsBox3D.area: src/core/geometry/qgsbox3d.h#L321 QgsBox3D.center: src/core/geometry/qgsbox3d.h#L314 QgsBox3D.combineWith: src/core/geometry/qgsbox3d.h#L382 @@ -1853,18 +1853,19 @@ QgsBox3D.contains: src/core/geometry/qgsbox3d.h#L356 QgsBox3D.contains: src/core/geometry/qgsbox3d.h#L364 QgsBox3D.contains: src/core/geometry/qgsbox3d.h#L375 QgsBox3D.depth: src/core/geometry/qgsbox3d.h#L307 -QgsBox3D.distanceTo: src/core/geometry/qgsbox3d.h#L402 -QgsBox3D.grow: src/core/geometry/qgsbox3d.h#L426 +QgsBox3D.distanceTo: src/core/geometry/qgsbox3d.h#L403 +QgsBox3D.distanceTo: src/core/geometry/qgsbox3d.h#L411 +QgsBox3D.grow: src/core/geometry/qgsbox3d.h#L435 QgsBox3D.height: src/core/geometry/qgsbox3d.h#L300 QgsBox3D.intersect: src/core/geometry/qgsbox3d.h#L331 QgsBox3D.intersects: src/core/geometry/qgsbox3d.h#L351 QgsBox3D.is2d: src/core/geometry/qgsbox3d.h#L337 QgsBox3D.is3D: src/core/geometry/qgsbox3d.h#L346 -QgsBox3D.isEmpty: src/core/geometry/qgsbox3d.h#L447 -QgsBox3D.isNull: src/core/geometry/qgsbox3d.h#L437 +QgsBox3D.isEmpty: src/core/geometry/qgsbox3d.h#L456 +QgsBox3D.isNull: src/core/geometry/qgsbox3d.h#L446 QgsBox3D.normalize: src/core/geometry/qgsbox3d.h#L286 -QgsBox3D.scale: src/core/geometry/qgsbox3d.h#L413 -QgsBox3D.scale: src/core/geometry/qgsbox3d.h#L420 +QgsBox3D.scale: src/core/geometry/qgsbox3d.h#L422 +QgsBox3D.scale: src/core/geometry/qgsbox3d.h#L429 QgsBox3D.set: src/core/geometry/qgsbox3d.h#L190 QgsBox3D.setNull: src/core/geometry/qgsbox3d.h#L281 QgsBox3D.setXMaximum: src/core/geometry/qgsbox3d.h#L204 @@ -1874,7 +1875,7 @@ QgsBox3D.setYMinimum: src/core/geometry/qgsbox3d.h#L225 QgsBox3D.setZMaximum: src/core/geometry/qgsbox3d.h#L260 QgsBox3D.setZMinimum: src/core/geometry/qgsbox3d.h#L253 QgsBox3D.toRectangle: src/core/geometry/qgsbox3d.h#L394 -QgsBox3D.toString: src/core/geometry/qgsbox3d.h#L456 +QgsBox3D.toString: src/core/geometry/qgsbox3d.h#L465 QgsBox3D.volume: src/core/geometry/qgsbox3d.h#L326 QgsBox3D.width: src/core/geometry/qgsbox3d.h#L293 QgsBox3D.xMaximum: src/core/geometry/qgsbox3d.h#L218 From 4f8fbc633afc17ea9b6b365ca2253a7420f24f51 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 30 Jan 2025 13:53:46 +1000 Subject: [PATCH 25/81] Update src/gui/vector/qgsvectorlayerproperties.cpp --- src/gui/vector/qgsvectorlayerproperties.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/vector/qgsvectorlayerproperties.cpp b/src/gui/vector/qgsvectorlayerproperties.cpp index 03d443228cca7..87deb70593369 100644 --- a/src/gui/vector/qgsvectorlayerproperties.cpp +++ b/src/gui/vector/qgsvectorlayerproperties.cpp @@ -1489,7 +1489,7 @@ void QgsVectorLayerProperties::mButtonRemoveJoin_clicked() // if current item is a child item, we should use its parent to be able to remove join if ( currentJoinItem && currentJoinItem->parent() ) { - currentJoinItem = mJoinTreeWidget->currentItem()->parent(); + currentJoinItem = currentJoinItem->parent(); } if ( !mLayer || !currentJoinItem ) From 84c126d4672b3b121b725b734b0a73baeda8e91e Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 14:19:15 +1000 Subject: [PATCH 26/81] Fix incorrect annotation HTML shown when clicking between annotations and HTML source view is enabled --- src/gui/qgsrichtexteditor.cpp | 10 +++++++--- src/gui/qgsrichtexteditor.h | 2 -- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/gui/qgsrichtexteditor.cpp b/src/gui/qgsrichtexteditor.cpp index fb7aed3d0f2b3..3b2cf206ffa6b 100644 --- a/src/gui/qgsrichtexteditor.cpp +++ b/src/gui/qgsrichtexteditor.cpp @@ -752,16 +752,20 @@ void QgsRichTextEditor::setText( const QString &text ) { if ( text.isEmpty() ) { - setPlainText( text ); + mTextEdit->setPlainText( text ); + mSourceEdit->clear(); return; } + if ( text[0] == '<' ) { - setHtml( text ); + mTextEdit->setHtml( text ); + mSourceEdit->setText( text ); } else { - setPlainText( text ); + mTextEdit->setPlainText( text ); + mSourceEdit->setText( text ); } } diff --git a/src/gui/qgsrichtexteditor.h b/src/gui/qgsrichtexteditor.h index c83551ddeda16..37968593d7378 100644 --- a/src/gui/qgsrichtexteditor.h +++ b/src/gui/qgsrichtexteditor.h @@ -162,8 +162,6 @@ class GUI_EXPORT QgsRichTextEditor : public QWidget, protected Ui::QgsRichTextEd void focusInEvent( QFocusEvent *event ) override; private slots: - void setPlainText( const QString &text ) { mTextEdit->setPlainText( text ); } - void setHtml( const QString &text ) { mTextEdit->setHtml( text ); } void textRemoveFormat(); void textRemoveAllFormat(); void textBold(); From 16839629b23fc03b2227bbce61c60553c8beee40 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 30 Jan 2025 13:59:35 +1000 Subject: [PATCH 27/81] Improve HTML text detection --- src/gui/qgsrichtexteditor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/qgsrichtexteditor.cpp b/src/gui/qgsrichtexteditor.cpp index 3b2cf206ffa6b..6bb022e976765 100644 --- a/src/gui/qgsrichtexteditor.cpp +++ b/src/gui/qgsrichtexteditor.cpp @@ -757,7 +757,8 @@ void QgsRichTextEditor::setText( const QString &text ) return; } - if ( text[0] == '<' ) + const thread_local QRegularExpression sIsHtmlRx( QStringLiteral( "^\\s*<" ) ); + if ( sIsHtmlRx.match( text ).hasMatch() ) { mTextEdit->setHtml( text ); mSourceEdit->setText( text ); From 5af35f6290fb7ea31ff5afec04e7d6cf459dd3e3 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 10:59:58 +1000 Subject: [PATCH 28/81] Cleanup unnecessary old cmake debug message --- resources/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index fdac9c286247b..af25a73af2a14 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -90,7 +90,6 @@ endif() ADD_QGIS_RESOURCES("${CMAKE_CURRENT_SOURCE_DIR}" resources DEST_RESOURCE_FILES "${RESOURCES_FILES}") -message(STATUS "Using PROJ >= 6 srs database.") set(SRSDB srs6.db) add_custom_command( From 9fab88eb4eea05b29d006544f3cda7b8d0cae574 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 11:00:08 +1000 Subject: [PATCH 29/81] Require PROJ >= 8.2 --- CMakeLists.txt | 4 ++++ INSTALL.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e283e40d65c1e..9b50255bd5542 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,6 +435,10 @@ if(WITH_CORE) # required find_package(Proj REQUIRED) message(STATUS "Found Proj: ${PROJ_VERSION} ${PROJ_DIR}") + if(PROJ_VERSION_MAJOR LESS 8 OR (PROJ_VERSION_MAJOR EQUAL 8 AND (PROJ_VERSION_MINOR LESS 2))) + message(FATAL_ERROR "Cannot build QGIS using Proj older than 8.2") + endif(PROJ_VERSION_MAJOR LESS 8 OR (PROJ_VERSION_MAJOR EQUAL 8 AND (PROJ_VERSION_MINOR LESS 2))) + find_package(GEOS REQUIRED) message(STATUS "Found Geos: ${GEOS_VERSION} ${GEOS_DIR}") find_package(GDAL REQUIRED) diff --git a/INSTALL.md b/INSTALL.md index cb724361d3101..b710e4feba0c1 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -106,7 +106,7 @@ Required build tools: Required build dependencies: * Qt >= 5.15.2 -* Proj >= 7.2.0 +* Proj >= 8.2.0 * GEOS >= 3.9 * Sqlite3 >= 3.0.0 * SpatiaLite >= 4.2.0 From 977f861276eef776f989080e2e6cdb20dc75b516 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 11:03:09 +1000 Subject: [PATCH 30/81] Remove misleading comment --- src/core/proj/qgscoordinatetransform.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/core/proj/qgscoordinatetransform.cpp b/src/core/proj/qgscoordinatetransform.cpp index cf7963adda94e..2b584b2824d76 100644 --- a/src/core/proj/qgscoordinatetransform.cpp +++ b/src/core/proj/qgscoordinatetransform.cpp @@ -788,9 +788,6 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double * #endif // use proj4 to do the transform - - // if the source/destination projection is lat/long, convert the points to radians - // prior to transforming ProjData projData = d->threadLocalProjData(); int projResult = 0; From af584b34ca7314d3f161d5a9fed03944e0090707 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 11:22:52 +1000 Subject: [PATCH 31/81] Remove duplicate proj version checks, support for very old proj versions --- cmake/FindProj.cmake | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/cmake/FindProj.cmake b/cmake/FindProj.cmake index 3feb785fa6be7..ba1b9c243aa8f 100644 --- a/cmake/FindProj.cmake +++ b/cmake/FindProj.cmake @@ -30,7 +30,6 @@ if(NOT PROJ_FOUND) OR NOT CMAKE_FIND_FRAMEWORK) SET (CMAKE_FIND_FRAMEWORK_save ${CMAKE_FIND_FRAMEWORK} CACHE STRING "" FORCE) SET (CMAKE_FIND_FRAMEWORK "ONLY" CACHE STRING "" FORCE) - #FIND_PATH(PROJ_INCLUDE_DIR PROJ/proj_api.h) FIND_LIBRARY(PROJ_LIBRARY PROJ) IF (PROJ_LIBRARY) # FIND_PATH doesn't add "Headers" for a framework @@ -39,17 +38,11 @@ if(NOT PROJ_FOUND) SET (CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK_save} CACHE STRING "" FORCE) ENDIF () ENDIF (APPLE) - - FIND_PATH(PROJ_INCLUDE_DIR proj_api.h + + FIND_PATH(PROJ_INCLUDE_DIR proj.h "$ENV{INCLUDE}" "$ENV{LIB_DIR}/include" - ) - IF (NOT PROJ_INCLUDE_DIR) - FIND_PATH(PROJ_INCLUDE_DIR proj.h - "$ENV{INCLUDE}" - "$ENV{LIB_DIR}/include" - ) - ENDIF (NOT PROJ_INCLUDE_DIR) + ) FIND_LIBRARY(PROJ_LIBRARY NAMES proj_i proj PATHS "$ENV{LIB}" @@ -67,23 +60,6 @@ if(NOT PROJ_FOUND) STRING(REGEX REPLACE "^.*PROJ_VERSION_MINOR +([0-9]+).*$" "\\1" PROJ_VERSION_MINOR "${proj_version}") STRING(REGEX REPLACE "^.*PROJ_VERSION_PATCH +([0-9]+).*$" "\\1" PROJ_VERSION_PATCH "${proj_version}") STRING(CONCAT PROJ_VERSION_STR "(" ${PROJ_VERSION_MAJOR} "." ${PROJ_VERSION_MINOR} "." ${PROJ_VERSION_PATCH} ")") - IF ((PROJ_VERSION_MAJOR EQUAL 7) AND ((PROJ_VERSION_MINOR LESS 2) OR (PROJ_VERSION_MAJOR LESS 7))) - MESSAGE (FATAL_ERROR "Cannot build QGIS using Proj ${PROJ_VERSION_MAJOR}.${PROJ_VERSION_MINOR}.${PROJ_VERSION_PATCH} Use 7.2.0 or higher.") - ENDIF ((PROJ_VERSION_MAJOR EQUAL 7) AND ((PROJ_VERSION_MINOR LESS 2) OR (PROJ_VERSION_MAJOR LESS 7))) - ELSE(EXISTS ${PROJ_INCLUDE_DIR}/proj.h AND EXISTS ${PROJ_INCLUDE_DIR}/proj_experimental.h) - FILE(READ ${PROJ_INCLUDE_DIR}/proj_api.h proj_version) - STRING(REGEX REPLACE "^.*PJ_VERSION ([0-9]+).*$" "\\1" PJ_VERSION "${proj_version}") - - # This will break if 4.10.0 ever will be released (highly unlikely) - STRING(REGEX REPLACE "([0-9])([0-9])([0-9])" "\\1" PROJ_VERSION_MAJOR "${PJ_VERSION}") - STRING(REGEX REPLACE "([0-9])([0-9])([0-9])" "\\2" PROJ_VERSION_MINOR "${PJ_VERSION}") - STRING(REGEX REPLACE "([0-9])([0-9])([0-9])" "\\3" PROJ_VERSION_PATCH "${PJ_VERSION}") - STRING(CONCAT PROJ_VERSION_STR "(" ${PROJ_VERSION_MAJOR} "." ${PROJ_VERSION_MINOR} "." ${PROJ_VERSION_PATCH} ")") - - # Minimum Proj version required is 4.9.3 - IF ((PROJ_VERSION_MAJOR EQUAL 4) AND ((PROJ_VERSION_MINOR LESS 9) OR ((PROJ_VERSION_MINOR EQUAL 9) AND (PROJ_VERSION_PATCH LESS 3)))) - MESSAGE(FATAL_ERROR "Found Proj: ${PROJ_VERSION_MAJOR}.${PROJ_VERSION_MINOR}.${PROJ_VERSION_PATCH}. Cannot build QGIS using Proj older than 4.9.3.") - ENDIF((PROJ_VERSION_MAJOR EQUAL 4) AND ((PROJ_VERSION_MINOR LESS 9) OR ((PROJ_VERSION_MINOR EQUAL 9) AND (PROJ_VERSION_PATCH LESS 3)))) ENDIF(EXISTS ${PROJ_INCLUDE_DIR}/proj.h AND EXISTS ${PROJ_INCLUDE_DIR}/proj_experimental.h) IF (NOT PROJ_FIND_QUIETLY) MESSAGE(STATUS "Found Proj: ${PROJ_LIBRARY} version ${PROJ_VERSION_MAJOR} ${PROJ_VERSION_STR}") From 10eb24711b4617ca177cc4b57996801628856513 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 11:34:50 +1000 Subject: [PATCH 32/81] Reluctantly allow 8.1 for mac builds --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b50255bd5542..f2c4d90cda7bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,9 +435,9 @@ if(WITH_CORE) # required find_package(Proj REQUIRED) message(STATUS "Found Proj: ${PROJ_VERSION} ${PROJ_DIR}") - if(PROJ_VERSION_MAJOR LESS 8 OR (PROJ_VERSION_MAJOR EQUAL 8 AND (PROJ_VERSION_MINOR LESS 2))) - message(FATAL_ERROR "Cannot build QGIS using Proj older than 8.2") - endif(PROJ_VERSION_MAJOR LESS 8 OR (PROJ_VERSION_MAJOR EQUAL 8 AND (PROJ_VERSION_MINOR LESS 2))) + if(PROJ_VERSION_MAJOR LESS 8 OR (PROJ_VERSION_MAJOR EQUAL 8 AND (PROJ_VERSION_MINOR LESS 1))) + message(FATAL_ERROR "Cannot build QGIS using Proj older than 8.1") + endif(PROJ_VERSION_MAJOR LESS 8 OR (PROJ_VERSION_MAJOR EQUAL 8 AND (PROJ_VERSION_MINOR LESS 1))) find_package(GEOS REQUIRED) message(STATUS "Found Geos: ${GEOS_VERSION} ${GEOS_DIR}") From 8c99b4c39cb052ee4fdeb2d4f357bc49902c77e7 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 11:43:27 +1000 Subject: [PATCH 33/81] Remove dead code from PROJ <8.1 --- .../proj/qgscoordinatereferencesystem.sip.in | 12 - ...gscoordinatereferencesystemregistry.sip.in | 6 - .../proj/qgscoordinatereferencesystem.sip.in | 16 +- ...gscoordinatereferencesystemregistry.sip.in | 6 - .../proj/qgscoordinatereferencesystem.cpp | 12 - src/core/proj/qgscoordinatereferencesystem.h | 17 +- .../qgscoordinatereferencesystemregistry.cpp | 4 - .../qgscoordinatereferencesystemregistry.h | 4 - src/core/proj/qgscoordinatetransform.cpp | 6 - src/core/proj/qgscoordinatetransform_p.cpp | 8 - src/core/proj/qgsellipsoidutils.cpp | 2 - src/core/proj/qgsprojutils.cpp | 4 - src/core/proj/qgsprojutils.h | 9 - .../core/testqgscoordinatereferencesystem.cpp | 2 - tests/src/core/testqgscoordinatetransform.cpp | 4 - tests/src/python/test_provider_oracle.py | 24 +- tests/src/python/test_qgsdatumtransforms.py | 295 ++----- tests/src/python/test_qgsellipsoidutils.py | 15 +- .../test_qgsvectorlayerprofilegenerator.py | 828 ++++++------------ 19 files changed, 355 insertions(+), 919 deletions(-) diff --git a/python/PyQt6/core/auto_generated/proj/qgscoordinatereferencesystem.sip.in b/python/PyQt6/core/auto_generated/proj/qgscoordinatereferencesystem.sip.in index 1ffebdd7f58ac..9c5d7453ab1e8 100644 --- a/python/PyQt6/core/auto_generated/proj/qgscoordinatereferencesystem.sip.in +++ b/python/PyQt6/core/auto_generated/proj/qgscoordinatereferencesystem.sip.in @@ -850,12 +850,6 @@ be returned. In the case of a compound crs, this method will always return the datum ensemble for the horizontal component. -.. warning:: - - This method requires PROJ 8.0 or later - -:raises QgsNotSupportedException: on QGIS builds based on PROJ 7 or earlier. - .. versionadded:: 3.20 %End @@ -863,12 +857,6 @@ be returned. %Docstring Attempts to retrieve the name of the celestial body associated with the CRS (e.g. "Earth"). -.. warning:: - - This method requires PROJ 8.1 or later - -:raises QgsNotSupportedException: on QGIS builds based on PROJ 8.0 or earlier. - .. versionadded:: 3.20 %End diff --git a/python/PyQt6/core/auto_generated/proj/qgscoordinatereferencesystemregistry.sip.in b/python/PyQt6/core/auto_generated/proj/qgscoordinatereferencesystemregistry.sip.in index 1df531255497e..55044defbf28d 100644 --- a/python/PyQt6/core/auto_generated/proj/qgscoordinatereferencesystemregistry.sip.in +++ b/python/PyQt6/core/auto_generated/proj/qgscoordinatereferencesystemregistry.sip.in @@ -128,12 +128,6 @@ The map keys correspond to PROJ operation IDs. %Docstring Returns a list of all known celestial bodies. -.. warning:: - - This method requires PROJ 8.1 or later - -:raises QgsNotSupportedException: on QGIS builds based on PROJ 8.0 or earlier. - .. versionadded:: 3.20 %End diff --git a/python/core/auto_generated/proj/qgscoordinatereferencesystem.sip.in b/python/core/auto_generated/proj/qgscoordinatereferencesystem.sip.in index f83c3850070a6..b33cfa95148ad 100644 --- a/python/core/auto_generated/proj/qgscoordinatereferencesystem.sip.in +++ b/python/core/auto_generated/proj/qgscoordinatereferencesystem.sip.in @@ -839,7 +839,7 @@ plate-fixed. .. versionadded:: 3.20 %End - QgsDatumEnsemble datumEnsemble() const throw( QgsNotSupportedException ); + QgsDatumEnsemble datumEnsemble() const; %Docstring Attempts to retrieve datum ensemble details from the CRS. @@ -850,25 +850,13 @@ be returned. In the case of a compound crs, this method will always return the datum ensemble for the horizontal component. -.. warning:: - - This method requires PROJ 8.0 or later - -:raises QgsNotSupportedException: on QGIS builds based on PROJ 7 or earlier. - .. versionadded:: 3.20 %End - QString celestialBodyName() const throw( QgsNotSupportedException ); + QString celestialBodyName() const; %Docstring Attempts to retrieve the name of the celestial body associated with the CRS (e.g. "Earth"). -.. warning:: - - This method requires PROJ 8.1 or later - -:raises QgsNotSupportedException: on QGIS builds based on PROJ 8.0 or earlier. - .. versionadded:: 3.20 %End diff --git a/python/core/auto_generated/proj/qgscoordinatereferencesystemregistry.sip.in b/python/core/auto_generated/proj/qgscoordinatereferencesystemregistry.sip.in index 1df531255497e..55044defbf28d 100644 --- a/python/core/auto_generated/proj/qgscoordinatereferencesystemregistry.sip.in +++ b/python/core/auto_generated/proj/qgscoordinatereferencesystemregistry.sip.in @@ -128,12 +128,6 @@ The map keys correspond to PROJ operation IDs. %Docstring Returns a list of all known celestial bodies. -.. warning:: - - This method requires PROJ 8.1 or later - -:raises QgsNotSupportedException: on QGIS builds based on PROJ 8.0 or earlier. - .. versionadded:: 3.20 %End diff --git a/src/core/proj/qgscoordinatereferencesystem.cpp b/src/core/proj/qgscoordinatereferencesystem.cpp index 5b4d2ff63dfc0..ec02aa463449d 100644 --- a/src/core/proj/qgscoordinatereferencesystem.cpp +++ b/src/core/proj/qgscoordinatereferencesystem.cpp @@ -1431,13 +1431,9 @@ QString QgsCoordinateReferenceSystem::celestialBodyName() const if ( !pj ) return QString(); -#if PROJ_VERSION_MAJOR>8 || (PROJ_VERSION_MAJOR==8 && PROJ_VERSION_MINOR>=1) PJ_CONTEXT *context = QgsProjContext::get(); return QString( proj_get_celestial_body_name( context, pj ) ); -#else - throw QgsNotSupportedException( QObject::tr( "Retrieving celestial body requires a QGIS build based on PROJ 8.1 or later" ) ); -#endif } void QgsCoordinateReferenceSystem::setCoordinateEpoch( double epoch ) @@ -1466,7 +1462,6 @@ QgsDatumEnsemble QgsCoordinateReferenceSystem::datumEnsemble() const if ( !pj ) return res; -#if PROJ_VERSION_MAJOR>=8 PJ_CONTEXT *context = QgsProjContext::get(); QgsProjUtils::proj_pj_unique_ptr ensemble = QgsProjUtils::crsToDatumEnsemble( pj ); @@ -1498,9 +1493,6 @@ QgsDatumEnsemble QgsCoordinateReferenceSystem::datumEnsemble() const res.mMembers << details; } return res; -#else - throw QgsNotSupportedException( QObject::tr( "Calculating datum ensembles requires a QGIS build based on PROJ 8.0 or later" ) ); -#endif } QgsProjectionFactors QgsCoordinateReferenceSystem::factors( const QgsPoint &point ) const @@ -1688,11 +1680,7 @@ void QgsCoordinateReferenceSystem::setProjString( const QString &proj4String ) { #ifdef QGISDEBUG const int errNo = proj_context_errno( ctx ); -#if PROJ_VERSION_MAJOR>=8 QgsDebugError( QStringLiteral( "proj string rejected: %1" ).arg( proj_context_errno_string( ctx, errNo ) ) ); -#else - QgsDebugError( QStringLiteral( "proj string rejected: %1" ).arg( proj_errno_string( errNo ) ) ); -#endif #endif d->mIsValid = false; } diff --git a/src/core/proj/qgscoordinatereferencesystem.h b/src/core/proj/qgscoordinatereferencesystem.h index acf51f56c74f5..79d2e139cae30 100644 --- a/src/core/proj/qgscoordinatereferencesystem.h +++ b/src/core/proj/qgscoordinatereferencesystem.h @@ -48,13 +48,8 @@ class QgsProjOperation; struct PJconsts; typedef struct PJconsts PJ; -#if PROJ_VERSION_MAJOR>=8 struct pj_ctx; typedef struct pj_ctx PJ_CONTEXT; -#else -struct projCtx_t; -typedef struct projCtx_t PJ_CONTEXT; -#endif #endif // forward declaration for sqlite3 @@ -776,24 +771,16 @@ class CORE_EXPORT QgsCoordinateReferenceSystem * * \note In the case of a compound crs, this method will always return the datum ensemble for the horizontal component. * - * \warning This method requires PROJ 8.0 or later - * - * \throws QgsNotSupportedException on QGIS builds based on PROJ 7 or earlier. - * * \since QGIS 3.20 */ - QgsDatumEnsemble datumEnsemble() const SIP_THROW( QgsNotSupportedException ); + QgsDatumEnsemble datumEnsemble() const; /** * Attempts to retrieve the name of the celestial body associated with the CRS (e.g. "Earth"). * - * \warning This method requires PROJ 8.1 or later - * - * \throws QgsNotSupportedException on QGIS builds based on PROJ 8.0 or earlier. - * * \since QGIS 3.20 */ - QString celestialBodyName() const SIP_THROW( QgsNotSupportedException ); + QString celestialBodyName() const; /** * Sets the coordinate \a epoch, as a decimal year. diff --git a/src/core/proj/qgscoordinatereferencesystemregistry.cpp b/src/core/proj/qgscoordinatereferencesystemregistry.cpp index c2fa197821418..061ff1c256768 100644 --- a/src/core/proj/qgscoordinatereferencesystemregistry.cpp +++ b/src/core/proj/qgscoordinatereferencesystemregistry.cpp @@ -380,7 +380,6 @@ QMap QgsCoordinateReferenceSystemRegistry::projOperat QList< QgsCelestialBody> QgsCoordinateReferenceSystemRegistry::celestialBodies() const { -#if PROJ_VERSION_MAJOR>8 || (PROJ_VERSION_MAJOR==8 && PROJ_VERSION_MINOR>=1) static QList< QgsCelestialBody > sCelestialBodies; static std::once_flag initialized; std::call_once( initialized, [] @@ -409,9 +408,6 @@ QList< QgsCelestialBody> QgsCoordinateReferenceSystemRegistry::celestialBodies() } ); return sCelestialBodies; -#else - throw QgsNotSupportedException( QObject::tr( "Retrieving celestial bodies requires a QGIS build based on PROJ 8.1 or later" ) ); -#endif } QSet QgsCoordinateReferenceSystemRegistry::authorities() const diff --git a/src/core/proj/qgscoordinatereferencesystemregistry.h b/src/core/proj/qgscoordinatereferencesystemregistry.h index 89b1e83d4ae7b..cc82e5933b4f5 100644 --- a/src/core/proj/qgscoordinatereferencesystemregistry.h +++ b/src/core/proj/qgscoordinatereferencesystemregistry.h @@ -162,10 +162,6 @@ class CORE_EXPORT QgsCoordinateReferenceSystemRegistry : public QObject /** * Returns a list of all known celestial bodies. * - * \warning This method requires PROJ 8.1 or later - * - * \throws QgsNotSupportedException on QGIS builds based on PROJ 8.0 or earlier. - * * \since QGIS 3.20 */ QList< QgsCelestialBody > celestialBodies() const; diff --git a/src/core/proj/qgscoordinatetransform.cpp b/src/core/proj/qgscoordinatetransform.cpp index 2b584b2824d76..3ff63ed766ba8 100644 --- a/src/core/proj/qgscoordinatetransform.cpp +++ b/src/core/proj/qgscoordinatetransform.cpp @@ -193,10 +193,8 @@ bool QgsCoordinateTransform::isTransformationPossible( const QgsCoordinateRefere if ( !source.isValid() || !destination.isValid() ) return false; -#if PROJ_VERSION_MAJOR>8 || (PROJ_VERSION_MAJOR==8 && PROJ_VERSION_MINOR>=1) if ( source.celestialBodyName() != destination.celestialBodyName() ) return false; -#endif return true; } @@ -899,12 +897,8 @@ void QgsCoordinateTransform::transformCoords( int numPoints, double *x, double * const QString dir = ( direction == Qgis::TransformDirection::Forward ) ? QObject::tr( "Forward transform" ) : QObject::tr( "Inverse transform" ); -#if PROJ_VERSION_MAJOR>=8 PJ_CONTEXT *projContext = QgsProjContext::get(); const QString projError = !errorOccurredDuringFallbackOperation ? QString::fromUtf8( proj_context_errno_string( projContext, projResult ) ) : QObject::tr( "Fallback transform failed" ); -#else - const QString projError = !errorOccurredDuringFallbackOperation ? QString::fromUtf8( proj_errno_string( projResult ) ) : QObject::tr( "Fallback transform failed" ); -#endif const QString msg = QObject::tr( "%1 (%2 to %3) of%4%5Error: %6" ) .arg( dir, diff --git a/src/core/proj/qgscoordinatetransform_p.cpp b/src/core/proj/qgscoordinatetransform_p.cpp index ad0b9a5413ef5..dc972831cdd17 100644 --- a/src/core/proj/qgscoordinatetransform_p.cpp +++ b/src/core/proj/qgscoordinatetransform_p.cpp @@ -334,11 +334,7 @@ ProjData QgsCoordinateTransformPrivate::threadLocalProjData() const int errNo = proj_context_errno( context ); if ( errNo ) { -#if PROJ_VERSION_MAJOR>=8 nonAvailableError = QString( proj_context_errno_string( context, errNo ) ); -#else - nonAvailableError = QString( proj_errno_string( errNo ) ); -#endif } else { @@ -473,11 +469,7 @@ ProjData QgsCoordinateTransformPrivate::threadLocalProjData() const QStringList projErrors = errorLogger.errors(); if ( errNo ) { -#if PROJ_VERSION_MAJOR>=8 nonAvailableError = QString( proj_context_errno_string( context, errNo ) ); -#else - nonAvailableError = QString( proj_errno_string( errNo ) ); -#endif } else if ( !projErrors.empty() ) { diff --git a/src/core/proj/qgsellipsoidutils.cpp b/src/core/proj/qgsellipsoidutils.cpp index 87b240cab1f8e..4f1270131438f 100644 --- a/src/core/proj/qgsellipsoidutils.cpp +++ b/src/core/proj/qgsellipsoidutils.cpp @@ -271,9 +271,7 @@ QList QgsEllipsoidUtils::definitions() name.replace( '_', ' ' ); def.description = QStringLiteral( "%1 (%2:%3)" ).arg( name, authority, code ); -#if PROJ_VERSION_MAJOR>8 || (PROJ_VERSION_MAJOR==8 && PROJ_VERSION_MINOR>=1) def.celestialBodyName = proj_get_celestial_body_name( context, ellipsoid.get() ); -#endif double semiMajor, semiMinor, invFlattening; int semiMinorComputed = 0; diff --git a/src/core/proj/qgsprojutils.cpp b/src/core/proj/qgsprojutils.cpp index 453086b506226..f381644d301b2 100644 --- a/src/core/proj/qgsprojutils.cpp +++ b/src/core/proj/qgsprojutils.cpp @@ -340,7 +340,6 @@ QgsProjUtils::proj_pj_unique_ptr QgsProjUtils::crsToDatumEnsemble( const PJ *crs if ( !crs ) return nullptr; -#if PROJ_VERSION_MAJOR>=8 PJ_CONTEXT *context = QgsProjContext::get(); QgsProjUtils::proj_pj_unique_ptr candidate = crsToHorizontalCrs( crs ); if ( !candidate ) // purely vertical CRS @@ -350,9 +349,6 @@ QgsProjUtils::proj_pj_unique_ptr QgsProjUtils::crsToDatumEnsemble( const PJ *crs return nullptr; return QgsProjUtils::proj_pj_unique_ptr( proj_crs_get_datum_ensemble( context, candidate.get() ) ); -#else - throw QgsNotSupportedException( QObject::tr( "Calculating datum ensembles requires a QGIS build based on PROJ 8.0 or later" ) ); -#endif } void QgsProjUtils::proj_collecting_logger( void *user_data, int /*level*/, const char *message ) diff --git a/src/core/proj/qgsprojutils.h b/src/core/proj/qgsprojutils.h index 862e52a76b87e..a343df0d62041 100644 --- a/src/core/proj/qgsprojutils.h +++ b/src/core/proj/qgsprojutils.h @@ -206,10 +206,6 @@ class CORE_EXPORT QgsProjUtils * * \note In the case of a compound \a crs, this method will always return the datum ensemble for the horizontal component. * - * \warning This method requires PROJ 8.0 or later - * - * \throws QgsNotSupportedException on QGIS builds based on PROJ 7 or earlier. - * * \since QGIS 3.20 */ static proj_pj_unique_ptr crsToDatumEnsemble( const PJ *crs ); @@ -270,13 +266,8 @@ class CORE_EXPORT QgsProjUtils #ifndef SIP_RUN -#if PROJ_VERSION_MAJOR>=8 struct pj_ctx; typedef struct pj_ctx PJ_CONTEXT; -#else -struct projCtx_t; -typedef struct projCtx_t PJ_CONTEXT; -#endif /** * \class QgsProjContext diff --git a/tests/src/core/testqgscoordinatereferencesystem.cpp b/tests/src/core/testqgscoordinatereferencesystem.cpp index 912577d5eeb57..2c5370d2ee902 100644 --- a/tests/src/core/testqgscoordinatereferencesystem.cpp +++ b/tests/src/core/testqgscoordinatereferencesystem.cpp @@ -1672,7 +1672,6 @@ void TestQgsCoordinateReferenceSystem::isDynamic() void TestQgsCoordinateReferenceSystem::celestialBody() { -#if ( PROJ_VERSION_MAJOR > 8 || ( PROJ_VERSION_MAJOR == 8 && PROJ_VERSION_MINOR >= 1 ) ) QgsCoordinateReferenceSystem crs; QCOMPARE( crs.celestialBodyName(), QString() ); @@ -1681,7 +1680,6 @@ void TestQgsCoordinateReferenceSystem::celestialBody() crs = QgsCoordinateReferenceSystem( QStringLiteral( "ESRI:104903" ) ); QCOMPARE( crs.celestialBodyName(), QStringLiteral( "Moon" ) ); -#endif } void TestQgsCoordinateReferenceSystem::operation() diff --git a/tests/src/core/testqgscoordinatetransform.cpp b/tests/src/core/testqgscoordinatetransform.cpp index d73357d96fcea..96aa62f3558f6 100644 --- a/tests/src/core/testqgscoordinatetransform.cpp +++ b/tests/src/core/testqgscoordinatetransform.cpp @@ -312,13 +312,11 @@ void TestQgsCoordinateTransform::constructorFlags() QVERIFY( !tr4.isShortCircuited() ); QVERIFY( tr4.mIgnoreImpossible ); -#if ( PROJ_VERSION_MAJOR > 8 || ( PROJ_VERSION_MAJOR == 8 && PROJ_VERSION_MINOR >= 1 ) ) QgsCoordinateTransform tr5( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ), QgsCoordinateReferenceSystem( QStringLiteral( "ESRI:104903" ) ), QgsProject::instance(), Qgis::CoordinateTransformationFlag::IgnoreImpossibleTransformations ); QVERIFY( !tr5.mBallparkTransformsAreAppropriate ); // crses are from two different celestial bodies, the transform is impossible and should be short-circuited QVERIFY( tr5.isShortCircuited() ); QVERIFY( tr5.mIgnoreImpossible ); -#endif } void TestQgsCoordinateTransform::scaleFactor_data() @@ -848,10 +846,8 @@ void TestQgsCoordinateTransform::testTransformationIsPossible() QVERIFY( !QgsCoordinateTransform::isTransformationPossible( QgsCoordinateReferenceSystem(), QgsCoordinateReferenceSystem() ) ); QVERIFY( QgsCoordinateTransform::isTransformationPossible( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) ) ); -#if ( PROJ_VERSION_MAJOR > 8 || ( PROJ_VERSION_MAJOR == 8 && PROJ_VERSION_MINOR >= 1 ) ) // crses from two different celestial bodies => transformation is not possible QVERIFY( !QgsCoordinateTransform::isTransformationPossible( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ), QgsCoordinateReferenceSystem( QStringLiteral( "ESRI:104903" ) ) ) ); -#endif } diff --git a/tests/src/python/test_provider_oracle.py b/tests/src/python/test_provider_oracle.py index b9d6a9590162d..c7e8dce1ec09d 100644 --- a/tests/src/python/test_provider_oracle.py +++ b/tests/src/python/test_provider_oracle.py @@ -214,15 +214,6 @@ def testAddFeatureWrongGeomType(self): """ pass - def testCrs(self): - """ - We override this test for Oracle provider, because without PROJ >= 7 - Oracle is not able to understand correctly some EPSG code (4326 for instance) - """ - # TODO remove this when PROJ will be >= 7 - if QgsProjUtils.projVersionMajor() >= 7: - super().testCrs() - # HERE GO THE PROVIDER SPECIFIC TESTS def testDateTimeTypes(self): vl = QgsVectorLayer( @@ -1710,10 +1701,7 @@ def testCreateEmptyLayer(self): ) self.assertTrue(query.next()) self.assertEqual(query.value(0), "GEOM") - # Cannot work with proj version < 7 because it cannot identify properly EPSG:4326 - # TODO remove this when PROJ will be >= 7 - if QgsProjUtils.projVersionMajor() >= 7: - self.assertEqual(query.value(1), 4326) + self.assertEqual(query.value(1), 4326) query.finish() # no feature, so we cannot guess the geometry type, so the layer is not valid @@ -1746,10 +1734,7 @@ def testCreateEmptyLayer(self): query.exec('SELECT "l"."GEOM"."SDO_SRID" from "QGIS"."EMPTY_LAYER" "l"') ) self.assertTrue(query.next()) - # Cannot work with proj version < 7 because it cannot identify properly EPSG:4326 - # TODO remove this when PROJ will be >= 7 - if QgsProjUtils.projVersionMajor() >= 7: - self.assertEqual(query.value(0), 4326) + self.assertEqual(query.value(0), 4326) query.finish() # now we can autodetect geom type and srid @@ -1759,10 +1744,7 @@ def testCreateEmptyLayer(self): "oracle", ) self.assertTrue(vl.isValid()) - # Cannot work with proj version < 7 because it cannot identify properly EPSG:4326 - # TODO remove this when PROJ will be >= 7 - if QgsProjUtils.projVersionMajor() >= 7: - self.assertEqual(vl.sourceCrs().authid(), "EPSG:4326") + self.assertEqual(vl.sourceCrs().authid(), "EPSG:4326") def testCreateAspatialLayer(self): """ diff --git a/tests/src/python/test_qgsdatumtransforms.py b/tests/src/python/test_qgsdatumtransforms.py index 877d8b9192906..bcd5d24a8dd48 100644 --- a/tests/src/python/test_qgsdatumtransforms.py +++ b/tests/src/python/test_qgsdatumtransforms.py @@ -98,170 +98,83 @@ def testOperations(self): self.assertEqual(ops[op1_index].accuracy, 0.01) self.assertEqual(len(ops[op1_index].grids), 0) - if QgsProjUtils.projVersionMajor() == 6: - op2_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" - ][0] - else: - op2_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" - ][0] + op2_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] self.assertTrue(ops[op2_index].name) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op2_index].proj, - "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg", - ) - else: - self.assertEqual( - ops[op2_index].proj, - "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", - ) + self.assertEqual( + ops[op2_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertEqual(ops[op2_index].accuracy, 0.05) self.assertEqual(len(ops[op2_index].grids), 1) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op2_index].grids[0].shortName, - "GDA94_GDA2020_conformal_and_distortion.gsb", - ) - else: - self.assertEqual( - ops[op2_index].grids[0].shortName, - "au_icsm_GDA94_GDA2020_conformal_and_distortion.tif", - ) - if QgsProjUtils.projVersionMajor() == 6: - self.assertTrue(ops[op2_index].grids[0].packageName) + self.assertEqual( + ops[op2_index].grids[0].shortName, + "au_icsm_GDA94_GDA2020_conformal_and_distortion.tif", + ) self.assertIn("http", ops[op2_index].grids[0].url) self.assertTrue(ops[op2_index].grids[0].directDownload) self.assertTrue(ops[op2_index].grids[0].openLicense) - if QgsProjUtils.projVersionMajor() == 6: - op3_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" - ][0] - else: - op3_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" - ][0] + op3_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] self.assertTrue(ops[op3_index].name) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op3_index].proj, - "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg", - ) - else: - self.assertEqual( - ops[op3_index].proj, - "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", - ) + self.assertEqual( + ops[op3_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertEqual(ops[op3_index].accuracy, 0.05) self.assertEqual(len(ops[op3_index].grids), 1) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op3_index].grids[0].shortName, "GDA94_GDA2020_conformal.gsb" - ) - else: - self.assertEqual( - ops[op3_index].grids[0].shortName, "au_icsm_GDA94_GDA2020_conformal.tif" - ) - if QgsProjUtils.projVersionMajor() == 6: - self.assertTrue(ops[op3_index].grids[0].packageName) + self.assertEqual( + ops[op3_index].grids[0].shortName, "au_icsm_GDA94_GDA2020_conformal.tif" + ) self.assertIn("http", ops[op3_index].grids[0].url) self.assertTrue(ops[op3_index].grids[0].directDownload) self.assertTrue(ops[op3_index].grids[0].openLicense) - if QgsProjUtils.projVersionMajor() == 6: - op4_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_cocos_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" - ][0] - else: - op4_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_cocos_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" - ][0] + op4_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_cocos_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] self.assertTrue(ops[op4_index].name) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op4_index].proj, - "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_cocos_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg", - ) - else: - self.assertEqual( - ops[op4_index].proj, - "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_cocos_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", - ) + self.assertEqual( + ops[op4_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_cocos_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertEqual(ops[op4_index].accuracy, 0.05) self.assertEqual(len(ops[op4_index].grids), 1) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op4_index].grids[0].shortName, - "GDA94_GDA2020_conformal_cocos_island.gsb", - ) - else: - self.assertEqual( - ops[op4_index].grids[0].shortName, - "au_icsm_GDA94_GDA2020_conformal_cocos_island.tif", - ) - if QgsProjUtils.projVersionMajor() == 6: - self.assertTrue(ops[op4_index].grids[0].packageName) + self.assertEqual( + ops[op4_index].grids[0].shortName, + "au_icsm_GDA94_GDA2020_conformal_cocos_island.tif", + ) self.assertIn("http", ops[op4_index].grids[0].url) - if QgsProjUtils.projVersionMajor() == 6: - op5_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_christmas_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" - ][0] - else: - op5_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_christmas_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" - ][0] + op5_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_christmas_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" + ][0] self.assertTrue(ops[op5_index].name) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op5_index].proj, - "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_christmas_island.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg", - ) - else: - self.assertEqual( - ops[op5_index].proj, - "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_christmas_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", - ) + self.assertEqual( + ops[op5_index].proj, + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_christmas_island.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg", + ) self.assertEqual(ops[op5_index].accuracy, 0.05) self.assertEqual(len(ops[op5_index].grids), 1) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op5_index].grids[0].shortName, - "GDA94_GDA2020_conformal_christmas_island.gsb", - ) - else: - self.assertEqual( - ops[op5_index].grids[0].shortName, - "au_icsm_GDA94_GDA2020_conformal_christmas_island.tif", - ) - if QgsProjUtils.projVersionMajor() == 6: - self.assertTrue(ops[op5_index].grids[0].packageName) + self.assertEqual( + ops[op5_index].grids[0].shortName, + "au_icsm_GDA94_GDA2020_conformal_christmas_island.tif", + ) self.assertIn("http", ops[op5_index].grids[0].url) # uses a pivot datum (technically a proj test, but this will help me sleep at night ;) @@ -287,86 +200,43 @@ def testOperations(self): self.assertEqual(ops[op1_index].accuracy, 0.01) self.assertEqual(len(ops[op1_index].grids), 0) - if QgsProjUtils.projVersionMajor() == 6: - op2_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" - ][0] - else: - op2_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" - ][0] + op2_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" + ][0] self.assertTrue(ops[op2_index].name) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op2_index].proj, - "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", - ) - else: - self.assertEqual( - ops[op2_index].proj, - "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", - ) + self.assertEqual( + ops[op2_index].proj, + "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", + ) self.assertEqual(ops[op2_index].accuracy, 0.05) self.assertEqual(len(ops[op2_index].grids), 1) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op2_index].grids[0].shortName, - "GDA94_GDA2020_conformal_and_distortion.gsb", - ) - else: - self.assertEqual( - ops[op2_index].grids[0].shortName, - "au_icsm_GDA94_GDA2020_conformal_and_distortion.tif", - ) - if QgsProjUtils.projVersionMajor() == 6: - self.assertTrue(ops[op2_index].grids[0].packageName) + self.assertEqual( + ops[op2_index].grids[0].shortName, + "au_icsm_GDA94_GDA2020_conformal_and_distortion.tif", + ) self.assertIn("http", ops[op2_index].grids[0].url) self.assertTrue(ops[op2_index].grids[0].directDownload) self.assertTrue(ops[op2_index].grids[0].openLicense) - if QgsProjUtils.projVersionMajor() == 6: - op3_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" - ][0] - else: - op3_index = [ - i - for i in range(len(ops)) - if ops[i].proj - == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" - ][0] + op3_index = [ + i + for i in range(len(ops)) + if ops[i].proj + == "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80" + ][0] self.assertTrue(ops[op3_index].name) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op3_index].proj, - "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=GDA94_GDA2020_conformal.gsb +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", - ) - else: - self.assertEqual( - ops[op3_index].proj, - "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", - ) + self.assertEqual( + ops[op3_index].proj, + "+proj=pipeline +step +inv +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80 +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal.tif +step +proj=lcc +lat_0=-37 +lon_0=145 +lat_1=-36 +lat_2=-38 +x_0=2500000 +y_0=2500000 +ellps=GRS80", + ) self.assertEqual(ops[op3_index].accuracy, 0.05) self.assertEqual(len(ops[op3_index].grids), 1) - if QgsProjUtils.projVersionMajor() == 6: - self.assertEqual( - ops[op3_index].grids[0].shortName, "GDA94_GDA2020_conformal.gsb" - ) - else: - self.assertEqual( - ops[op3_index].grids[0].shortName, "au_icsm_GDA94_GDA2020_conformal.tif" - ) - if QgsProjUtils.projVersionMajor() == 6: - self.assertTrue(ops[op3_index].grids[0].packageName) + self.assertEqual( + ops[op3_index].grids[0].shortName, "au_icsm_GDA94_GDA2020_conformal.tif" + ) self.assertIn("http", ops[op3_index].grids[0].url) self.assertTrue(ops[op3_index].grids[0].directDownload) self.assertTrue(ops[op3_index].grids[0].openLicense) @@ -393,7 +263,6 @@ def testNoLasLos(self): self.assertTrue(ops[1].name) self.assertTrue(ops[1].proj) - @unittest.skipIf(QgsProjUtils.projVersionMajor() < 8, "Not a proj >= 8 build") def testDatumEnsembles(self): """ Test datum ensemble details diff --git a/tests/src/python/test_qgsellipsoidutils.py b/tests/src/python/test_qgsellipsoidutils.py index 250318fb1939a..d07b64beac41e 100644 --- a/tests/src/python/test_qgsellipsoidutils.py +++ b/tests/src/python/test_qgsellipsoidutils.py @@ -11,7 +11,7 @@ __copyright__ = "Copyright 2017, The QGIS Project" -from qgis.core import QgsEllipsoidUtils, QgsProjUtils +from qgis.core import QgsEllipsoidUtils import unittest from qgis.testing import start_app, QgisTestCase @@ -105,11 +105,7 @@ def testDefinitions(self): self.assertEqual(gany_defs.acronym, gany_id) self.assertEqual(gany_defs.description, "Ganymede 2000 IAU IAG (ESRI:107916)") - if QgsProjUtils.projVersionMajor() > 8 or ( - QgsProjUtils.projVersionMajor() == 8 - and QgsProjUtils.projVersionMinor() >= 1 - ): - self.assertEqual(gany_defs.celestialBodyName, "Ganymede") + self.assertEqual(gany_defs.celestialBodyName, "Ganymede") self.assertTrue(gany_defs.parameters.valid) self.assertEqual(gany_defs.parameters.semiMajor, 2632345.0) @@ -118,13 +114,6 @@ def testDefinitions(self): self.assertFalse(gany_defs.parameters.useCustomParameters) self.assertEqual(gany_defs.parameters.crs.authid(), "") - @unittest.skipIf( - QgsProjUtils.projVersionMajor() < 8 - or ( - QgsProjUtils.projVersionMajor() == 8 and QgsProjUtils.projVersionMinor() < 1 - ), - "Not a proj >= 8.1 build", - ) def testCelestialBodies(self): bodies = QgsEllipsoidUtils.celestialBodies() diff --git a/tests/src/python/test_qgsvectorlayerprofilegenerator.py b/tests/src/python/test_qgsvectorlayerprofilegenerator.py index e1fac53c446b1..d6c59e08a9fef 100644 --- a/tests/src/python/test_qgsvectorlayerprofilegenerator.py +++ b/tests/src/python/test_qgsvectorlayerprofilegenerator.py @@ -225,20 +225,12 @@ def testPointGenerationTerrain(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - {175.6: 69.5, 31.2: 69.5, 1242.5: 55.2}, - ) - self.assertAlmostEqual(results.zRange().lower(), 55.249, 2) - self.assertAlmostEqual(results.zRange().upper(), 69.5, 2) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 67.2, 175.6: 65.8, 1242.5: 52.2}, - ) - self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 67.25, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {175.6: 69.5, 31.2: 69.5, 1242.5: 55.2}, + ) + self.assertAlmostEqual(results.zRange().lower(), 55.249, 2) + self.assertAlmostEqual(results.zRange().upper(), 69.5, 2) # 70 meters tolerance req.setTolerance(70) @@ -246,20 +238,12 @@ def testPointGenerationTerrain(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - {175.6: 69.5, 31.2: 69.5, 1223.2: 56.8, 1242.5: 55.2}, - ) - self.assertAlmostEqual(results.zRange().lower(), 55.249, 2) - self.assertAlmostEqual(results.zRange().upper(), 69.5, 2) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 67.2, 175.6: 65.8, 1242.5: 52.2}, - ) - self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 67.25, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {175.6: 69.5, 31.2: 69.5, 1223.2: 56.8, 1242.5: 55.2}, + ) + self.assertAlmostEqual(results.zRange().lower(), 55.249, 2) + self.assertAlmostEqual(results.zRange().upper(), 69.5, 2) def testPointGenerationRelative(self): """ @@ -301,20 +285,12 @@ def testPointGenerationRelative(self): generator = vl.createProfileGenerator(req) self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 333.5, 175.6: 333.5, 1242.5: 267.0}, - ) - self.assertAlmostEqual(results.zRange().lower(), 267.0, 2) - self.assertAlmostEqual(results.zRange().upper(), 333.5, 2) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 331.2, 175.6: 329.8, 1242.5: 264.0}, - ) - self.assertAlmostEqual(results.zRange().lower(), 264.0, 2) - self.assertAlmostEqual(results.zRange().upper(), 331.25, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {31.2: 333.5, 175.6: 333.5, 1242.5: 267.0}, + ) + self.assertAlmostEqual(results.zRange().lower(), 267.0, 2) + self.assertAlmostEqual(results.zRange().upper(), 333.5, 2) def testPointGenerationRelativeExtrusion(self): """ @@ -355,39 +331,21 @@ def testPointGenerationRelativeExtrusion(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 333.5, 175.6: 333.5, 1242.5: 267.0}, - ) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - {31.2: 331.2, 175.6: 329.8, 1242.5: 264.0}, - ) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + {31.2: 333.5, 175.6: 333.5, 1242.5: 267.0}, + ) - if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "LineString Z (-347395 6632649.6 333.5, -347395 6632649.6 340.5)", - "LineString Z (-347533.4 6632692.2 333.5, -347533.4 6632692.2 340.5)", - "LineString Z (-346399.2 6632265.6 267, -346399.2 6632265.6 274)", - ], - ) - self.assertAlmostEqual(results.zRange().lower(), 267.0, 2) - self.assertAlmostEqual(results.zRange().upper(), 340.5, 2) - else: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "LineString Z (-347395 6632649.6 329.8, -347395 6632649.6 336.8)", - "LineString Z (-347533.4 6632692.2 331.3, -347533.4 6632692.2 338.3)", - "LineString Z (-346399.2 6632265.6 264, -346399.2 6632265.6 271)", - ], - ) - self.assertAlmostEqual(results.zRange().lower(), 264.0, 2) - self.assertAlmostEqual(results.zRange().upper(), 338.25, 2) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "LineString Z (-347395 6632649.6 333.5, -347395 6632649.6 340.5)", + "LineString Z (-347533.4 6632692.2 333.5, -347533.4 6632692.2 340.5)", + "LineString Z (-346399.2 6632265.6 267, -346399.2 6632265.6 274)", + ], + ) + self.assertAlmostEqual(results.zRange().lower(), 267.0, 2) + self.assertAlmostEqual(results.zRange().upper(), 340.5, 2) def testPointGenerationMultiPoint(self): vl = QgsVectorLayer("MultipointZ?crs=EPSG:27700", "trees", "memory") @@ -624,34 +582,19 @@ def testLineGenerationTerrain(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 675.2: 66.5, - 1195.7: 49.2, - 1223.1: 50.0, - 1272.0: 53.8, - 1339.4: 58.2, - 1444.4: 58.2, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 66.5, 2) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 675.2: 62.7, - 1195.7: 53.0, - 1223.1: 56.0, - 1272.0: 58.2, - 1339.4: 57.5, - 1444.4: 52.2, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 62.7499, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 66.5, + 1195.7: 49.2, + 1223.1: 50.0, + 1272.0: 53.8, + 1339.4: 58.2, + 1444.4: 58.2, + }, + ) + self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) + self.assertAlmostEqual(results.zRange().upper(), 66.5, 2) def testLineGenerationTerrainTolerance(self): vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") @@ -698,47 +641,25 @@ def testLineGenerationTerrainTolerance(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 2), - { - 675.09: 66.5, - 675.24: 66.5, - 1195.73: 49.25, - 1195.74: 49.25, - 1223.14: 50.0, - 1223.15: 50.0, - 1271.97: 53.75, - 1271.99: 53.75, - 1339.33: 58.25, - 1339.51: 58.25, - 1444.18: 58.25, - 1444.59: 58.25, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 66.5, 2) - else: - # TODO find a way to test with an older proj version - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 2), - { - 675.09: 66.5, - 675.24: 66.5, - 1195.73: 49.25, - 1195.74: 49.25, - 1223.14: 50.0, - 1223.15: 50.0, - 1271.97: 53.75, - 1271.99: 53.75, - 1339.33: 58.25, - 1339.51: 58.25, - 1444.18: 58.25, - 1444.59: 58.25, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 62.7499, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 675.09: 66.5, + 675.24: 66.5, + 1195.73: 49.25, + 1195.74: 49.25, + 1223.14: 50.0, + 1223.15: 50.0, + 1271.97: 53.75, + 1271.99: 53.75, + 1339.33: 58.25, + 1339.51: 58.25, + 1444.18: 58.25, + 1444.59: 58.25, + }, + ) + self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) + self.assertAlmostEqual(results.zRange().upper(), 66.5, 2) # 1 meter tolerance tolerance = 1 @@ -748,47 +669,25 @@ def testLineGenerationTerrainTolerance(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 2), - { - 674.43: 66.5, - 675.91: 66.5, - 1195.73: 49.25, - 1195.91: 49.25, - 1223.06: 50.0, - 1223.23: 50.0, - 1271.86: 53.75, - 1272.1: 53.75, - 1338.5: 58.25, - 1340.34: 58.25, - 1442.29: 56.75, - 1446.48: 57.5, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 66.5, 2) - else: - # TODO find a way to test with an older proj version - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 2), - { - 675.09: 66.5, - 675.24: 66.5, - 1195.73: 49.25, - 1195.74: 49.25, - 1223.14: 50.0, - 1223.15: 50.0, - 1271.97: 53.75, - 1271.99: 53.75, - 1339.33: 58.25, - 1339.51: 58.25, - 1444.18: 58.25, - 1444.59: 58.25, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 62.7499, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 674.43: 66.5, + 675.91: 66.5, + 1195.73: 49.25, + 1195.91: 49.25, + 1223.06: 50.0, + 1223.23: 50.0, + 1271.86: 53.75, + 1272.1: 53.75, + 1338.5: 58.25, + 1340.34: 58.25, + 1442.29: 56.75, + 1446.48: 57.5, + }, + ) + self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) + self.assertAlmostEqual(results.zRange().upper(), 66.5, 2) # 15 meters tolerance tolerance = 15 @@ -798,47 +697,25 @@ def testLineGenerationTerrainTolerance(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 2), - { - 664.1: 65.75, - 686.24: 67.25, - 1195.73: 49.25, - 1198.44: 49.25, - 1221.85: 50.0, - 1224.44: 49.25, - 1270.21: 54.5, - 1273.75: 53.0, - 1325.61: 59.0, - 1353.23: 57.5, - 1412.92: 56.0, - 1475.85: 57.5, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 67.25, 2) - else: - # TODO find a way to test with an older proj version - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 2), - { - 675.09: 66.5, - 675.24: 66.5, - 1195.73: 49.25, - 1195.74: 49.25, - 1223.14: 50.0, - 1223.15: 50.0, - 1271.97: 53.75, - 1271.99: 53.75, - 1339.33: 58.25, - 1339.51: 58.25, - 1444.18: 58.25, - 1444.59: 58.25, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 52.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 62.7499, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 2), + { + 664.1: 65.75, + 686.24: 67.25, + 1195.73: 49.25, + 1198.44: 49.25, + 1221.85: 50.0, + 1224.44: 49.25, + 1270.21: 54.5, + 1273.75: 53.0, + 1325.61: 59.0, + 1353.23: 57.5, + 1412.92: 56.0, + 1475.85: 57.5, + }, + ) + self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) + self.assertAlmostEqual(results.zRange().upper(), 67.25, 2) def testLineGenerationRelative(self): vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") @@ -881,34 +758,19 @@ def testLineGenerationRelative(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 675.2: 84.2, - 1195.7: 86.8, - 1223.1: 81.4, - 1272.0: 90.0, - 1339.4: 98.7, - 1444.4: 100.0, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 81.358, 2) - self.assertAlmostEqual(results.zRange().upper(), 100.009, 2) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 675.2: 80.5, - 1195.7: 90.5, - 1223.1: 87.4, - 1272.0: 94.5, - 1339.4: 98.0, - 1444.4: 94.0, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 80.4564, 2) - self.assertAlmostEqual(results.zRange().upper(), 97.9811, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 84.2, + 1195.7: 86.8, + 1223.1: 81.4, + 1272.0: 90.0, + 1339.4: 98.7, + 1444.4: 100.0, + }, + ) + self.assertAlmostEqual(results.zRange().lower(), 81.358, 2) + self.assertAlmostEqual(results.zRange().upper(), 100.009, 2) def testLineGenerationRelativeExtrusion(self): vl = QgsVectorLayer("LineStringZ?crs=EPSG:27700", "lines", "memory") @@ -953,59 +815,31 @@ def testLineGenerationRelativeExtrusion(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 675.2: 84.2, - 1195.7: 86.8, - 1223.1: 81.4, - 1272.0: 90.0, - 1339.4: 98.7, - 1444.4: 100.0, - }, - ) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 675.2: 80.5, - 1195.7: 90.5, - 1223.1: 87.4, - 1272.0: 94.5, - 1339.4: 98.0, - 1444.4: 94.0, - }, - ) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 675.2: 84.2, + 1195.7: 86.8, + 1223.1: 81.4, + 1272.0: 90.0, + 1339.4: 98.7, + 1444.4: 100.0, + }, + ) - if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "LineString Z (-346549.8 6632363.9 81.4, -346549.8 6632363.9 88.4)", - "LineString Z (-346501.4 6632357.8 90, -346501.4 6632357.8 97)", - "LineString Z (-346434.5 6632349.2 98.7, -346434.5 6632349.2 105.7)", - "LineString Z (-346384.6 6632279.1 100, -346384.6 6632279.1 107)", - "LineString Z (-346577 6632367.4 86.8, -346577 6632367.4 93.8)", - "LineString Z (-347062.8 6632554.4 84.2, -347062.8 6632554.4 91.2)", - ], - ) - self.assertAlmostEqual(results.zRange().lower(), 81.3588, 2) - self.assertAlmostEqual(results.zRange().upper(), 107.009, 2) - else: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "LineString Z (-346549.8 6632363.9 87.4, -346549.8 6632363.9 94.4)", - "LineString Z (-346501.4 6632357.8 94.5, -346501.4 6632357.8 101.5)", - "LineString Z (-346434.5 6632349.2 98, -346434.5 6632349.2 105)", - "LineString Z (-346384.6 6632279.1 94, -346384.6 6632279.1 101)", - "LineString Z (-346577 6632367.4 90.5, -346577 6632367.4 97.5)", - "LineString Z (-347062.8 6632554.4 80.5, -347062.8 6632554.4 87.5)", - ], - ) - self.assertAlmostEqual(results.zRange().lower(), 80.45645, 2) - self.assertAlmostEqual(results.zRange().upper(), 104.9811499, 2) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "LineString Z (-346549.8 6632363.9 81.4, -346549.8 6632363.9 88.4)", + "LineString Z (-346501.4 6632357.8 90, -346501.4 6632357.8 97)", + "LineString Z (-346434.5 6632349.2 98.7, -346434.5 6632349.2 105.7)", + "LineString Z (-346384.6 6632279.1 100, -346384.6 6632279.1 107)", + "LineString Z (-346577 6632367.4 86.8, -346577 6632367.4 93.8)", + "LineString Z (-347062.8 6632554.4 84.2, -347062.8 6632554.4 91.2)", + ], + ) + self.assertAlmostEqual(results.zRange().lower(), 81.3588, 2) + self.assertAlmostEqual(results.zRange().upper(), 107.009, 2) def testPolygonGenerationAbsolute(self): vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") @@ -1110,54 +944,29 @@ def testPolygonGenerationTerrain(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 1041.8: 55.3, - 1042.4: 55.2, - 1049.5: 55.2, - 1070.2: 55.2, - 1073.1: 55.2, - 1074.8: 55.3, - 1078.9: 54.5, - 1083.9: 54.5, - 1091.1: 54.5, - 1186.8: 49.3, - 1189.8: 49.2, - 1192.7: 49.2, - 1199.2: 49.2, - 1450.0: 53.0, - 1455.6: 53.0, - 1458.1: 53.0, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 55.250, 2) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 1041.8: 48.5, - 1042.4: 48.5, - 1049.5: 48.5, - 1070.2: 48.5, - 1073.1: 48.5, - 1074.8: 48.5, - 1078.9: 48.5, - 1083.9: 48.5, - 1091.1: 48.5, - 1186.8: 52.3, - 1189.8: 52.2, - 1192.7: 52.2, - 1199.2: 52.2, - 1450.0: 54.5, - 1455.6: 54.5, - 1458.1: 54.5, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 48.5, 2) - self.assertAlmostEqual(results.zRange().upper(), 54.500000, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 55.3, + 1042.4: 55.2, + 1049.5: 55.2, + 1070.2: 55.2, + 1073.1: 55.2, + 1074.8: 55.3, + 1078.9: 54.5, + 1083.9: 54.5, + 1091.1: 54.5, + 1186.8: 49.3, + 1189.8: 49.2, + 1192.7: 49.2, + 1199.2: 49.2, + 1450.0: 53.0, + 1455.6: 53.0, + 1458.1: 53.0, + }, + ) + self.assertAlmostEqual(results.zRange().lower(), 49.25, 2) + self.assertAlmostEqual(results.zRange().upper(), 55.250, 2) def testPolygonGenerationRelative(self): vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") @@ -1199,76 +1008,39 @@ def testPolygonGenerationRelative(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 1041.8: 60.3, - 1042.4: 60.2, - 1049.5: 60.2, - 1070.2: 60.2, - 1073.1: 60.2, - 1074.8: 60.3, - 1078.9: 62.0, - 1083.9: 62.0, - 1091.1: 62.0, - 1186.8: 59.3, - 1189.8: 59.2, - 1192.7: 59.2, - 1199.2: 59.2, - 1450.0: 65.5, - 1455.6: 65.5, - 1458.1: 65.5, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 59.2499, 2) - self.assertAlmostEqual(results.zRange().upper(), 65.5000, 2) - - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 1041.8: 53.5, - 1042.4: 53.5, - 1049.5: 53.5, - 1070.2: 53.5, - 1073.1: 53.5, - 1074.8: 53.5, - 1078.9: 56.0, - 1083.9: 56.0, - 1091.1: 56.0, - 1186.8: 62.3, - 1189.8: 62.3, - 1192.7: 62.3, - 1199.2: 62.2, - 1450.0: 67.0, - 1455.6: 67.0, - 1458.1: 67.0, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 53.5, 2) - self.assertAlmostEqual(results.zRange().upper(), 67.000, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 60.3, + 1042.4: 60.2, + 1049.5: 60.2, + 1070.2: 60.2, + 1073.1: 60.2, + 1074.8: 60.3, + 1078.9: 62.0, + 1083.9: 62.0, + 1091.1: 62.0, + 1186.8: 59.3, + 1189.8: 59.2, + 1192.7: 59.2, + 1199.2: 59.2, + 1450.0: 65.5, + 1455.6: 65.5, + 1458.1: 65.5, + }, + ) + self.assertAlmostEqual(results.zRange().lower(), 59.2499, 2) + self.assertAlmostEqual(results.zRange().upper(), 65.5000, 2) - if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "MultiLineString Z ((-346718.7 6632419.8 60.3, -346712 6632417.4 60.3),(-346719.3 6632420 60.3, -346718.7 6632419.8 60.2),(-346689.7 6632409.5 60.3, -346688.2 6632409 60.3),(-346692.5 6632410.5 60.3, -346689.7 6632409.5 60.3))", - "MultiLineString Z ((-346684.3 6632407.6 62, -346679.6 6632406 62),(-346679.6 6632406 62, -346672.8 6632403.6 62))", - "MultiLineString Z ((-346582.6 6632371.7 59.3, -346579.7 6632370.7 59.3),(-346579.7 6632370.7 59.3, -346577 6632369.7 59.2, -346570.8 6632367.9 59.3))", - "MultiLineString Z ((-346387.6 6632223.9 65.5, -346384.8 6632219 65.5),(-346384.8 6632219 65.5, -346383.5 6632216.9 65.5))", - ], - ) - else: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "MultiLineString Z ((-346684.3 6632407.6 56, -346679.6 6632406 56),(-346679.6 6632406 56, -346672.8 6632403.6 56))", - "MultiLineString Z ((-346718.7 6632419.8 53.5, -346712 6632417.4 53.5),(-346719.3 6632420 53.5, -346718.7 6632419.8 53.5),(-346689.7 6632409.5 53.5, -346688.2 6632409 53.5),(-346692.5 6632410.5 53.5, -346689.7 6632409.5 53.5))", - "MultiLineString Z ((-346387.6 6632223.9 67, -346384.8 6632219 67),(-346384.8 6632219 67, -346383.5 6632216.9 67))", - "MultiLineString Z ((-346582.6 6632371.7 62.3, -346579.7 6632370.7 62.3),(-346579.7 6632370.7 62.3, -346577 6632369.7 62.3, -346570.8 6632367.9 62.3))", - ], - ) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiLineString Z ((-346718.7 6632419.8 60.3, -346712 6632417.4 60.3),(-346719.3 6632420 60.3, -346718.7 6632419.8 60.2),(-346689.7 6632409.5 60.3, -346688.2 6632409 60.3),(-346692.5 6632410.5 60.3, -346689.7 6632409.5 60.3))", + "MultiLineString Z ((-346684.3 6632407.6 62, -346679.6 6632406 62),(-346679.6 6632406 62, -346672.8 6632403.6 62))", + "MultiLineString Z ((-346582.6 6632371.7 59.3, -346579.7 6632370.7 59.3),(-346579.7 6632370.7 59.3, -346577 6632369.7 59.2, -346570.8 6632367.9 59.3))", + "MultiLineString Z ((-346387.6 6632223.9 65.5, -346384.8 6632219 65.5),(-346384.8 6632219 65.5, -346383.5 6632216.9 65.5))", + ], + ) def testPolygonGenerationRelativeExtrusion(self): vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") @@ -1312,75 +1084,39 @@ def testPolygonGenerationRelativeExtrusion(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 1041.8: 60.3, - 1042.4: 60.2, - 1049.5: 60.2, - 1070.2: 60.2, - 1073.1: 60.2, - 1074.8: 60.3, - 1078.9: 62.0, - 1083.9: 62.0, - 1091.1: 62.0, - 1186.8: 59.3, - 1189.8: 59.2, - 1192.7: 59.2, - 1199.2: 59.2, - 1450.0: 65.5, - 1455.6: 65.5, - 1458.1: 65.5, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 59.2499, 2) - self.assertAlmostEqual(results.zRange().upper(), 72.50000, 2) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 1041.8: 53.5, - 1042.4: 53.5, - 1049.5: 53.5, - 1070.2: 53.5, - 1073.1: 53.5, - 1074.8: 53.5, - 1078.9: 56.0, - 1083.9: 56.0, - 1091.1: 56.0, - 1186.8: 62.3, - 1189.8: 62.3, - 1192.7: 62.3, - 1199.2: 62.2, - 1450.0: 67.0, - 1455.6: 67.0, - 1458.1: 67.0, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 53.5, 2) - self.assertAlmostEqual(results.zRange().upper(), 74.00000, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.8: 60.3, + 1042.4: 60.2, + 1049.5: 60.2, + 1070.2: 60.2, + 1073.1: 60.2, + 1074.8: 60.3, + 1078.9: 62.0, + 1083.9: 62.0, + 1091.1: 62.0, + 1186.8: 59.3, + 1189.8: 59.2, + 1192.7: 59.2, + 1199.2: 59.2, + 1450.0: 65.5, + 1455.6: 65.5, + 1458.1: 65.5, + }, + ) + self.assertAlmostEqual(results.zRange().lower(), 59.2499, 2) + self.assertAlmostEqual(results.zRange().upper(), 72.50000, 2) - if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "MultiPolygon Z (((-346718.7 6632419.8 60.3, -346712 6632417.4 60.3, -346712 6632417.4 67.3, -346718.7 6632419.8 67.3, -346718.7 6632419.8 60.3)),((-346719.3 6632420 60.3, -346718.7 6632419.8 60.2, -346718.7 6632419.8 67.3, -346719.3 6632420 67.3, -346719.3 6632420 60.3)),((-346689.7 6632409.5 60.3, -346688.2 6632409 60.3, -346688.2 6632409 67.3, -346689.7 6632409.5 67.3, -346689.7 6632409.5 60.3)),((-346692.5 6632410.5 60.3, -346689.7 6632409.5 60.3, -346689.7 6632409.5 67.3, -346692.5 6632410.5 67.3, -346692.5 6632410.5 60.3)))", - "MultiPolygon Z (((-346684.3 6632407.6 62, -346679.6 6632406 62, -346679.6 6632406 69, -346684.3 6632407.6 69, -346684.3 6632407.6 62)),((-346679.6 6632406 62, -346672.8 6632403.6 62, -346672.8 6632403.6 69, -346679.6 6632406 69, -346679.6 6632406 62)))", - "MultiPolygon Z (((-346582.6 6632371.7 59.3, -346579.7 6632370.7 59.3, -346579.7 6632370.7 66.3, -346582.6 6632371.7 66.3, -346582.6 6632371.7 59.3)),((-346579.7 6632370.7 59.3, -346577 6632369.7 59.2, -346570.8 6632367.9 59.3, -346570.8 6632367.9 66.3, -346577 6632369.7 66.3, -346579.7 6632370.7 66.3, -346579.7 6632370.7 59.3)))", - "MultiPolygon Z (((-346387.6 6632223.9 65.5, -346384.8 6632219 65.5, -346384.8 6632219 72.5, -346387.6 6632223.9 72.5, -346387.6 6632223.9 65.5)),((-346384.8 6632219 65.5, -346383.5 6632216.9 65.5, -346383.5 6632216.9 72.5, -346384.8 6632219 72.5, -346384.8 6632219 65.5)))", - ], - ) - else: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "MultiPolygon Z (((-346684.3 6632407.6 56, -346679.6 6632406 56, -346679.6 6632406 63, -346684.3 6632407.6 63, -346684.3 6632407.6 56)),((-346679.6 6632406 56, -346672.8 6632403.6 56, -346672.8 6632403.6 63, -346679.6 6632406 63, -346679.6 6632406 56)))", - "MultiPolygon Z (((-346718.7 6632419.8 53.5, -346712 6632417.4 53.5, -346712 6632417.4 60.5, -346718.7 6632419.8 60.5, -346718.7 6632419.8 53.5)),((-346719.3 6632420 53.5, -346718.7 6632419.8 53.5, -346718.7 6632419.8 60.5, -346719.3 6632420 60.5, -346719.3 6632420 53.5)),((-346689.7 6632409.5 53.5, -346688.2 6632409 53.5, -346688.2 6632409 60.5, -346689.7 6632409.5 60.5, -346689.7 6632409.5 53.5)),((-346692.5 6632410.5 53.5, -346689.7 6632409.5 53.5, -346689.7 6632409.5 60.5, -346692.5 6632410.5 60.5, -346692.5 6632410.5 53.5)))", - "MultiPolygon Z (((-346387.6 6632223.9 67, -346384.8 6632219 67, -346384.8 6632219 74, -346387.6 6632223.9 74, -346387.6 6632223.9 67)),((-346384.8 6632219 67, -346383.5 6632216.9 67, -346383.5 6632216.9 74, -346384.8 6632219 74, -346384.8 6632219 67)))", - "MultiPolygon Z (((-346582.6 6632371.7 62.3, -346579.7 6632370.7 62.3, -346579.7 6632370.7 69.3, -346582.6 6632371.7 69.3, -346582.6 6632371.7 62.3)),((-346579.7 6632370.7 62.3, -346577 6632369.7 62.3, -346570.8 6632367.9 62.3, -346570.8 6632367.9 69.3, -346577 6632369.7 69.3, -346579.7 6632370.7 69.3, -346579.7 6632370.7 62.3)))", - ], - ) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiPolygon Z (((-346718.7 6632419.8 60.3, -346712 6632417.4 60.3, -346712 6632417.4 67.3, -346718.7 6632419.8 67.3, -346718.7 6632419.8 60.3)),((-346719.3 6632420 60.3, -346718.7 6632419.8 60.2, -346718.7 6632419.8 67.3, -346719.3 6632420 67.3, -346719.3 6632420 60.3)),((-346689.7 6632409.5 60.3, -346688.2 6632409 60.3, -346688.2 6632409 67.3, -346689.7 6632409.5 67.3, -346689.7 6632409.5 60.3)),((-346692.5 6632410.5 60.3, -346689.7 6632409.5 60.3, -346689.7 6632409.5 67.3, -346692.5 6632410.5 67.3, -346692.5 6632410.5 60.3)))", + "MultiPolygon Z (((-346684.3 6632407.6 62, -346679.6 6632406 62, -346679.6 6632406 69, -346684.3 6632407.6 69, -346684.3 6632407.6 62)),((-346679.6 6632406 62, -346672.8 6632403.6 62, -346672.8 6632403.6 69, -346679.6 6632406 69, -346679.6 6632406 62)))", + "MultiPolygon Z (((-346582.6 6632371.7 59.3, -346579.7 6632370.7 59.3, -346579.7 6632370.7 66.3, -346582.6 6632371.7 66.3, -346582.6 6632371.7 59.3)),((-346579.7 6632370.7 59.3, -346577 6632369.7 59.2, -346570.8 6632367.9 59.3, -346570.8 6632367.9 66.3, -346577 6632369.7 66.3, -346579.7 6632370.7 66.3, -346579.7 6632370.7 59.3)))", + "MultiPolygon Z (((-346387.6 6632223.9 65.5, -346384.8 6632219 65.5, -346384.8 6632219 72.5, -346387.6 6632223.9 72.5, -346387.6 6632223.9 65.5)),((-346384.8 6632219 65.5, -346383.5 6632216.9 65.5, -346383.5 6632216.9 72.5, -346384.8 6632219 72.5, -346384.8 6632219 65.5)))", + ], + ) def testPolygonGenerationRelativeExtrusionTolerance(self): vl = QgsVectorLayer("PolygonZ?crs=EPSG:27700", "lines", "memory") @@ -1428,81 +1164,45 @@ def testPolygonGenerationRelativeExtrusionTolerance(self): self.assertTrue(generator.generateProfile()) results = generator.takeResults() - if QgsProjUtils.projVersionMajor() >= 8: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 1041.0: 60.2, - 1042.2: 60.2, - 1042.9: 60.2, - 1048.2: 60.2, - 1050.8: 60.2, - 1066.9: 60.2, - 1073.4: 60.2, - 1076.2: 60.2, - 1077.9: 62.0, - 1079.9: 62.0, - 1089.9: 62.0, - 1092.2: 62.0, - 1185.4: 59.2, - 1188.2: 59.2, - 1192.6: 59.2, - 1192.7: 59.2, - 1197.9: 59.2, - 1200.4: 59.2, - 1449.3: 65.5, - 1450.1: 65.5, - 1451.1: 65.5, - 1458.1: 65.5, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 59.25, 2) - self.assertAlmostEqual(results.zRange().upper(), 65.5, 2) - else: - self.assertEqual( - self.round_dict(results.distanceToHeightMap(), 1), - { - 1041.8: 53.5, - 1042.4: 53.5, - 1049.5: 53.5, - 1070.2: 53.5, - 1073.1: 53.5, - 1074.8: 53.5, - 1078.9: 56.0, - 1083.9: 56.0, - 1091.1: 56.0, - 1186.8: 62.3, - 1189.8: 62.3, - 1192.7: 62.3, - 1199.2: 62.2, - 1450.0: 67.0, - 1455.6: 67.0, - 1458.1: 67.0, - }, - ) - self.assertAlmostEqual(results.zRange().lower(), 53.5, 2) - self.assertAlmostEqual(results.zRange().upper(), 74.00000, 2) + self.assertEqual( + self.round_dict(results.distanceToHeightMap(), 1), + { + 1041.0: 60.2, + 1042.2: 60.2, + 1042.9: 60.2, + 1048.2: 60.2, + 1050.8: 60.2, + 1066.9: 60.2, + 1073.4: 60.2, + 1076.2: 60.2, + 1077.9: 62.0, + 1079.9: 62.0, + 1089.9: 62.0, + 1092.2: 62.0, + 1185.4: 59.2, + 1188.2: 59.2, + 1192.6: 59.2, + 1192.7: 59.2, + 1197.9: 59.2, + 1200.4: 59.2, + 1449.3: 65.5, + 1450.1: 65.5, + 1451.1: 65.5, + 1458.1: 65.5, + }, + ) + self.assertAlmostEqual(results.zRange().lower(), 59.25, 2) + self.assertAlmostEqual(results.zRange().upper(), 65.5, 2) - if QgsProjUtils.projVersionMajor() >= 8: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "MultiLineString Z ((-346696.3 6632409.8 60.2, -346688.9 6632411.2 60.2, -346687.5 6632406.6 60.2),(-346718.9 6632417.7 60.2, -346719.5 6632421.6 60.2, -346718.2 6632421.7 60.2, -346712.5 6632419.7 60.2, -346711.5 6632415.1 60.2))", - "LineString Z (-346684.1 6632405.4 62, -346684.6 6632409.8 62, -346673.3 6632405.9 62, -346672.4 6632401.3 62)", - "LineString Z (-346571.4 6632370.2 59.3, -346570.2 6632365.6 59.3, -346577.6 6632367.8 59.3, -346577.7 6632367.9 59.3, -346581.9 6632369.4 59.3, -346583.2 6632374 59.3, -346576.4 6632371.6 59.3)", - "LineString Z (-346381.8 6632217.9 65.5, -346385.3 6632215.9 65.5, -346388.7 6632221.9 65.5, -346387 6632224.9 65.5, -346385.8 6632224.7 65.5)", - ], - ) - else: - self.assertCountEqual( - [g.asWkt(1) for g in results.asGeometries()], - [ - "MultiPolygon Z (((-346684.3 6632407.6 56, -346679.6 6632406 56, -346679.6 6632406 63, -346684.3 6632407.6 63, -346684.3 6632407.6 56)),((-346679.6 6632406 56, -346672.8 6632403.6 56, -346672.8 6632403.6 63, -346679.6 6632406 63, -346679.6 6632406 56)))", - "MultiPolygon Z (((-346718.7 6632419.8 53.5, -346712 6632417.4 53.5, -346712 6632417.4 60.5, -346718.7 6632419.8 60.5, -346718.7 6632419.8 53.5)),((-346719.3 6632420 53.5, -346718.7 6632419.8 53.5, -346718.7 6632419.8 60.5, -346719.3 6632420 60.5, -346719.3 6632420 53.5)),((-346689.7 6632409.5 53.5, -346688.2 6632409 53.5, -346688.2 6632409 60.5, -346689.7 6632409.5 60.5, -346689.7 6632409.5 53.5)),((-346692.5 6632410.5 53.5, -346689.7 6632409.5 53.5, -346689.7 6632409.5 60.5, -346692.5 6632410.5 60.5, -346692.5 6632410.5 53.5)))", - "MultiPolygon Z (((-346387.6 6632223.9 67, -346384.8 6632219 67, -346384.8 6632219 74, -346387.6 6632223.9 74, -346387.6 6632223.9 67)),((-346384.8 6632219 67, -346383.5 6632216.9 67, -346383.5 6632216.9 74, -346384.8 6632219 74, -346384.8 6632219 67)))", - "MultiPolygon Z (((-346582.6 6632371.7 62.3, -346579.7 6632370.7 62.3, -346579.7 6632370.7 69.3, -346582.6 6632371.7 69.3, -346582.6 6632371.7 62.3)),((-346579.7 6632370.7 62.3, -346577 6632369.7 62.3, -346570.8 6632367.9 62.3, -346570.8 6632367.9 69.3, -346577 6632369.7 69.3, -346579.7 6632370.7 69.3, -346579.7 6632370.7 62.3)))", - ], - ) + self.assertCountEqual( + [g.asWkt(1) for g in results.asGeometries()], + [ + "MultiLineString Z ((-346696.3 6632409.8 60.2, -346688.9 6632411.2 60.2, -346687.5 6632406.6 60.2),(-346718.9 6632417.7 60.2, -346719.5 6632421.6 60.2, -346718.2 6632421.7 60.2, -346712.5 6632419.7 60.2, -346711.5 6632415.1 60.2))", + "LineString Z (-346684.1 6632405.4 62, -346684.6 6632409.8 62, -346673.3 6632405.9 62, -346672.4 6632401.3 62)", + "LineString Z (-346571.4 6632370.2 59.3, -346570.2 6632365.6 59.3, -346577.6 6632367.8 59.3, -346577.7 6632367.9 59.3, -346581.9 6632369.4 59.3, -346583.2 6632374 59.3, -346576.4 6632371.6 59.3)", + "LineString Z (-346381.8 6632217.9 65.5, -346385.3 6632215.9 65.5, -346388.7 6632221.9 65.5, -346387 6632224.9 65.5, -346385.8 6632224.7 65.5)", + ], + ) def test25DPolygonGeneration(self): vl = QgsVectorLayer("PolygonZ?crs=EPSG:2056", "lines", "memory") From 5ccaad7f8058940ce8e7222ea80ca370127bf09c Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 13:24:13 +1000 Subject: [PATCH 34/81] Improve condition check --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2c4d90cda7bf..6771d37a1b8f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,9 +435,9 @@ if(WITH_CORE) # required find_package(Proj REQUIRED) message(STATUS "Found Proj: ${PROJ_VERSION} ${PROJ_DIR}") - if(PROJ_VERSION_MAJOR LESS 8 OR (PROJ_VERSION_MAJOR EQUAL 8 AND (PROJ_VERSION_MINOR LESS 1))) + if(PROJ_VERSION_MAJOR VERSION_LESS "8.1") message(FATAL_ERROR "Cannot build QGIS using Proj older than 8.1") - endif(PROJ_VERSION_MAJOR LESS 8 OR (PROJ_VERSION_MAJOR EQUAL 8 AND (PROJ_VERSION_MINOR LESS 1))) + endif(PROJ_VERSION_MAJOR VERSION_LESS "8.1") find_package(GEOS REQUIRED) message(STATUS "Found Geos: ${GEOS_VERSION} ${GEOS_DIR}") From 6257874a40b279148e8450ad465d46ebb5a0979b Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 13:24:33 +1000 Subject: [PATCH 35/81] Fix README --- INSTALL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/INSTALL.md b/INSTALL.md index b710e4feba0c1..3cd876bbf6291 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -106,7 +106,7 @@ Required build tools: Required build dependencies: * Qt >= 5.15.2 -* Proj >= 8.2.0 +* Proj >= 8.1.0 * GEOS >= 3.9 * Sqlite3 >= 3.0.0 * SpatiaLite >= 4.2.0 From ed6b7b9c1704320eb83077fbde3bfc3563b04a21 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 13:37:31 +1000 Subject: [PATCH 36/81] Fix check --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6771d37a1b8f3..ae18788eca5f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,9 +435,9 @@ if(WITH_CORE) # required find_package(Proj REQUIRED) message(STATUS "Found Proj: ${PROJ_VERSION} ${PROJ_DIR}") - if(PROJ_VERSION_MAJOR VERSION_LESS "8.1") + if(PROJ_VERSION VERSION_LESS "8.1") message(FATAL_ERROR "Cannot build QGIS using Proj older than 8.1") - endif(PROJ_VERSION_MAJOR VERSION_LESS "8.1") + endif(PROJ_VERSION VERSION_LESS "8.1") find_package(GEOS REQUIRED) message(STATUS "Found Geos: ${GEOS_VERSION} ${GEOS_DIR}") From 1b2b06d578526c8c63bc2c304a03b6d867412e3f Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 29 Jan 2025 14:04:04 +1000 Subject: [PATCH 37/81] Update CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae18788eca5f0..40bcbb956a1ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -437,7 +437,7 @@ if(WITH_CORE) message(STATUS "Found Proj: ${PROJ_VERSION} ${PROJ_DIR}") if(PROJ_VERSION VERSION_LESS "8.1") message(FATAL_ERROR "Cannot build QGIS using Proj older than 8.1") - endif(PROJ_VERSION VERSION_LESS "8.1") + endif() find_package(GEOS REQUIRED) message(STATUS "Found Geos: ${GEOS_VERSION} ${GEOS_DIR}") From ca8643eb8efdf3c1ba09655fe70d9d4906d54ecd Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 30 Jan 2025 08:49:09 +1000 Subject: [PATCH 38/81] Restore correct version of test --- tests/src/python/test_qgsdatumtransforms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/python/test_qgsdatumtransforms.py b/tests/src/python/test_qgsdatumtransforms.py index bcd5d24a8dd48..0b3e92aaf6879 100644 --- a/tests/src/python/test_qgsdatumtransforms.py +++ b/tests/src/python/test_qgsdatumtransforms.py @@ -102,7 +102,7 @@ def testOperations(self): i for i in range(len(ops)) if ops[i].proj - == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=GDA94_GDA2020_conformal_and_distortion.gsb +step +proj=unitconvert +xy_in=rad +xy_out=deg" + == "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=au_icsm_GDA94_GDA2020_conformal_and_distortion.tif +step +proj=unitconvert +xy_in=rad +xy_out=deg" ][0] self.assertTrue(ops[op2_index].name) self.assertEqual( From 91c4e96f665f7b58fc5b04434eb2f7e133c4fb64 Mon Sep 17 00:00:00 2001 From: qgis-bot Date: Thu, 30 Jan 2025 20:58:30 +0000 Subject: [PATCH 39/81] =?UTF-8?q?auto=20sipify=20=F0=9F=8D=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/PyQt6/core/class_map.yaml | 160 +++++++++++++++---------------- python/core/class_map.yaml | 160 +++++++++++++++---------------- 2 files changed, 160 insertions(+), 160 deletions(-) diff --git a/python/PyQt6/core/class_map.yaml b/python/PyQt6/core/class_map.yaml index f318f486f282d..30c3924f083d5 100644 --- a/python/PyQt6/core/class_map.yaml +++ b/python/PyQt6/core/class_map.yaml @@ -2620,91 +2620,91 @@ QgsCoordinateFormatter.formatX: src/core/qgscoordinateformatter.h#L75 QgsCoordinateFormatter.formatY: src/core/qgscoordinateformatter.h#L88 QgsCoordinateFormatter.separator: src/core/qgscoordinateformatter.h#L116 QgsCoordinateFormatter: src/core/qgscoordinateformatter.h#L39 -QgsCoordinateReferenceSystem.QVariant: src/core/proj/qgscoordinatereferencesystem.h#L280 -QgsCoordinateReferenceSystem.QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L256 -QgsCoordinateReferenceSystem.QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L271 -QgsCoordinateReferenceSystem.__repr__: src/core/proj/qgscoordinatereferencesystem.h#L1079 -QgsCoordinateReferenceSystem.authid: src/core/proj/qgscoordinatereferencesystem.h#L658 -QgsCoordinateReferenceSystem.axisOrdering: src/core/proj/qgscoordinatereferencesystem.h#L886 -QgsCoordinateReferenceSystem.bounds: src/core/proj/qgscoordinatereferencesystem.h#L937 -QgsCoordinateReferenceSystem.celestialBodyName: src/core/proj/qgscoordinatereferencesystem.h#L796 -QgsCoordinateReferenceSystem.clearRecentCoordinateReferenceSystems: src/core/proj/qgscoordinatereferencesystem.h#L1158 -QgsCoordinateReferenceSystem.coordinateEpoch: src/core/proj/qgscoordinatereferencesystem.h#L846 -QgsCoordinateReferenceSystem.createCompoundCrs: src/core/proj/qgscoordinatereferencesystem.h#L376 -QgsCoordinateReferenceSystem.createFromId: src/core/proj/qgscoordinatereferencesystem.h#L387 -QgsCoordinateReferenceSystem.createFromOgcWmsCrs: src/core/proj/qgscoordinatereferencesystem.h#L404 -QgsCoordinateReferenceSystem.createFromProj4: src/core/proj/qgscoordinatereferencesystem.h#L477 -QgsCoordinateReferenceSystem.createFromProj: src/core/proj/qgscoordinatereferencesystem.h#L511 -QgsCoordinateReferenceSystem.createFromSrid: src/core/proj/qgscoordinatereferencesystem.h#L415 -QgsCoordinateReferenceSystem.createFromSrsId: src/core/proj/qgscoordinatereferencesystem.h#L449 -QgsCoordinateReferenceSystem.createFromString: src/core/proj/qgscoordinatereferencesystem.h#L533 -QgsCoordinateReferenceSystem.createFromUserInput: src/core/proj/qgscoordinatereferencesystem.h#L555 -QgsCoordinateReferenceSystem.createFromWkt: src/core/proj/qgscoordinatereferencesystem.h#L432 -QgsCoordinateReferenceSystem.datumEnsemble: src/core/proj/qgscoordinatereferencesystem.h#L785 -QgsCoordinateReferenceSystem.description: src/core/proj/qgscoordinatereferencesystem.h#L667 -QgsCoordinateReferenceSystem.ellipsoidAcronym: src/core/proj/qgscoordinatereferencesystem.h#L698 -QgsCoordinateReferenceSystem.factors: src/core/proj/qgscoordinatereferencesystem.h#L859 -QgsCoordinateReferenceSystem.findMatchingProj: src/core/proj/qgscoordinatereferencesystem.h#L596 -QgsCoordinateReferenceSystem.fromEpsgId: src/core/proj/qgscoordinatereferencesystem.h#L313 -QgsCoordinateReferenceSystem.fromOgcWmsCrs: src/core/proj/qgscoordinatereferencesystem.h#L302 -QgsCoordinateReferenceSystem.fromProj4: src/core/proj/qgscoordinatereferencesystem.h#L325 -QgsCoordinateReferenceSystem.fromProj: src/core/proj/qgscoordinatereferencesystem.h#L334 -QgsCoordinateReferenceSystem.fromSrsId: src/core/proj/qgscoordinatereferencesystem.h#L359 -QgsCoordinateReferenceSystem.fromWkt: src/core/proj/qgscoordinatereferencesystem.h#L346 -QgsCoordinateReferenceSystem.geographicCrsAuthId: src/core/proj/qgscoordinatereferencesystem.h#L1076 -QgsCoordinateReferenceSystem.hasAxisInverted: src/core/proj/qgscoordinatereferencesystem.h#L876 -QgsCoordinateReferenceSystem.hasVerticalAxis: src/core/proj/qgscoordinatereferencesystem.h#L1073 -QgsCoordinateReferenceSystem.horizontalCrs: src/core/proj/qgscoordinatereferencesystem.h#L1051 -QgsCoordinateReferenceSystem.invalidateCache: src/core/proj/qgscoordinatereferencesystem.h#L1180 -QgsCoordinateReferenceSystem.isDeprecated: src/core/proj/qgscoordinatereferencesystem.h#L753 -QgsCoordinateReferenceSystem.isDynamic: src/core/proj/qgscoordinatereferencesystem.h#L769 -QgsCoordinateReferenceSystem.isGeographic: src/core/proj/qgscoordinatereferencesystem.h#L759 -QgsCoordinateReferenceSystem.isValid: src/core/proj/qgscoordinatereferencesystem.h#L570 -QgsCoordinateReferenceSystem.mapUnits: src/core/proj/qgscoordinatereferencesystem.h#L928 -QgsCoordinateReferenceSystem.nativeFormat: src/core/proj/qgscoordinatereferencesystem.h#L1028 -QgsCoordinateReferenceSystem.operation: src/core/proj/qgscoordinatereferencesystem.h#L867 -QgsCoordinateReferenceSystem.postgisSrid: src/core/proj/qgscoordinatereferencesystem.h#L644 -QgsCoordinateReferenceSystem.projectionAcronym: src/core/proj/qgscoordinatereferencesystem.h#L690 -QgsCoordinateReferenceSystem.pushRecentCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L1144 -QgsCoordinateReferenceSystem.readXml: src/core/proj/qgscoordinatereferencesystem.h#L607 -QgsCoordinateReferenceSystem.recentProjections: src/core/proj/qgscoordinatereferencesystem.h#L1130 -QgsCoordinateReferenceSystem.removeRecentCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L1151 -QgsCoordinateReferenceSystem.saveAsUserCrs: src/core/proj/qgscoordinatereferencesystem.h#L1006 -QgsCoordinateReferenceSystem.setCoordinateEpoch: src/core/proj/qgscoordinatereferencesystem.h#L821 -QgsCoordinateReferenceSystem.setNativeFormat: src/core/proj/qgscoordinatereferencesystem.h#L1017 -QgsCoordinateReferenceSystem.setValidationHint: src/core/proj/qgscoordinatereferencesystem.h#L978 -QgsCoordinateReferenceSystem.setupESRIWktFix: src/core/proj/qgscoordinatereferencesystem.h#L567 -QgsCoordinateReferenceSystem.srsid: src/core/proj/qgscoordinatereferencesystem.h#L636 -QgsCoordinateReferenceSystem.syncDatabase: src/core/proj/qgscoordinatereferencesystem.h#L991 -QgsCoordinateReferenceSystem.toGeographicCrs: src/core/proj/qgscoordinatereferencesystem.h#L1039 -QgsCoordinateReferenceSystem.toOgcUri: src/core/proj/qgscoordinatereferencesystem.h#L945 -QgsCoordinateReferenceSystem.toOgcUrn: src/core/proj/qgscoordinatereferencesystem.h#L953 -QgsCoordinateReferenceSystem.toProj4: src/core/proj/qgscoordinatereferencesystem.h#L725 -QgsCoordinateReferenceSystem.toProj: src/core/proj/qgscoordinatereferencesystem.h#L739 -QgsCoordinateReferenceSystem.toWkt: src/core/proj/qgscoordinatereferencesystem.h#L711 -QgsCoordinateReferenceSystem.type: src/core/proj/qgscoordinatereferencesystem.h#L746 -QgsCoordinateReferenceSystem.updateDefinition: src/core/proj/qgscoordinatereferencesystem.h#L973 -QgsCoordinateReferenceSystem.userFriendlyIdentifier: src/core/proj/qgscoordinatereferencesystem.h#L682 -QgsCoordinateReferenceSystem.validate: src/core/proj/qgscoordinatereferencesystem.h#L584 -QgsCoordinateReferenceSystem.validationHint: src/core/proj/qgscoordinatereferencesystem.h#L983 -QgsCoordinateReferenceSystem.verticalCrs: src/core/proj/qgscoordinatereferencesystem.h#L1065 -QgsCoordinateReferenceSystem.writeXml: src/core/proj/qgscoordinatereferencesystem.h#L615 -QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L211 +QgsCoordinateReferenceSystem.QVariant: src/core/proj/qgscoordinatereferencesystem.h#L275 +QgsCoordinateReferenceSystem.QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L251 +QgsCoordinateReferenceSystem.QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L266 +QgsCoordinateReferenceSystem.__repr__: src/core/proj/qgscoordinatereferencesystem.h#L1066 +QgsCoordinateReferenceSystem.authid: src/core/proj/qgscoordinatereferencesystem.h#L653 +QgsCoordinateReferenceSystem.axisOrdering: src/core/proj/qgscoordinatereferencesystem.h#L873 +QgsCoordinateReferenceSystem.bounds: src/core/proj/qgscoordinatereferencesystem.h#L924 +QgsCoordinateReferenceSystem.celestialBodyName: src/core/proj/qgscoordinatereferencesystem.h#L783 +QgsCoordinateReferenceSystem.clearRecentCoordinateReferenceSystems: src/core/proj/qgscoordinatereferencesystem.h#L1145 +QgsCoordinateReferenceSystem.coordinateEpoch: src/core/proj/qgscoordinatereferencesystem.h#L833 +QgsCoordinateReferenceSystem.createCompoundCrs: src/core/proj/qgscoordinatereferencesystem.h#L371 +QgsCoordinateReferenceSystem.createFromId: src/core/proj/qgscoordinatereferencesystem.h#L382 +QgsCoordinateReferenceSystem.createFromOgcWmsCrs: src/core/proj/qgscoordinatereferencesystem.h#L399 +QgsCoordinateReferenceSystem.createFromProj4: src/core/proj/qgscoordinatereferencesystem.h#L472 +QgsCoordinateReferenceSystem.createFromProj: src/core/proj/qgscoordinatereferencesystem.h#L506 +QgsCoordinateReferenceSystem.createFromSrid: src/core/proj/qgscoordinatereferencesystem.h#L410 +QgsCoordinateReferenceSystem.createFromSrsId: src/core/proj/qgscoordinatereferencesystem.h#L444 +QgsCoordinateReferenceSystem.createFromString: src/core/proj/qgscoordinatereferencesystem.h#L528 +QgsCoordinateReferenceSystem.createFromUserInput: src/core/proj/qgscoordinatereferencesystem.h#L550 +QgsCoordinateReferenceSystem.createFromWkt: src/core/proj/qgscoordinatereferencesystem.h#L427 +QgsCoordinateReferenceSystem.datumEnsemble: src/core/proj/qgscoordinatereferencesystem.h#L776 +QgsCoordinateReferenceSystem.description: src/core/proj/qgscoordinatereferencesystem.h#L662 +QgsCoordinateReferenceSystem.ellipsoidAcronym: src/core/proj/qgscoordinatereferencesystem.h#L693 +QgsCoordinateReferenceSystem.factors: src/core/proj/qgscoordinatereferencesystem.h#L846 +QgsCoordinateReferenceSystem.findMatchingProj: src/core/proj/qgscoordinatereferencesystem.h#L591 +QgsCoordinateReferenceSystem.fromEpsgId: src/core/proj/qgscoordinatereferencesystem.h#L308 +QgsCoordinateReferenceSystem.fromOgcWmsCrs: src/core/proj/qgscoordinatereferencesystem.h#L297 +QgsCoordinateReferenceSystem.fromProj4: src/core/proj/qgscoordinatereferencesystem.h#L320 +QgsCoordinateReferenceSystem.fromProj: src/core/proj/qgscoordinatereferencesystem.h#L329 +QgsCoordinateReferenceSystem.fromSrsId: src/core/proj/qgscoordinatereferencesystem.h#L354 +QgsCoordinateReferenceSystem.fromWkt: src/core/proj/qgscoordinatereferencesystem.h#L341 +QgsCoordinateReferenceSystem.geographicCrsAuthId: src/core/proj/qgscoordinatereferencesystem.h#L1063 +QgsCoordinateReferenceSystem.hasAxisInverted: src/core/proj/qgscoordinatereferencesystem.h#L863 +QgsCoordinateReferenceSystem.hasVerticalAxis: src/core/proj/qgscoordinatereferencesystem.h#L1060 +QgsCoordinateReferenceSystem.horizontalCrs: src/core/proj/qgscoordinatereferencesystem.h#L1038 +QgsCoordinateReferenceSystem.invalidateCache: src/core/proj/qgscoordinatereferencesystem.h#L1167 +QgsCoordinateReferenceSystem.isDeprecated: src/core/proj/qgscoordinatereferencesystem.h#L748 +QgsCoordinateReferenceSystem.isDynamic: src/core/proj/qgscoordinatereferencesystem.h#L764 +QgsCoordinateReferenceSystem.isGeographic: src/core/proj/qgscoordinatereferencesystem.h#L754 +QgsCoordinateReferenceSystem.isValid: src/core/proj/qgscoordinatereferencesystem.h#L565 +QgsCoordinateReferenceSystem.mapUnits: src/core/proj/qgscoordinatereferencesystem.h#L915 +QgsCoordinateReferenceSystem.nativeFormat: src/core/proj/qgscoordinatereferencesystem.h#L1015 +QgsCoordinateReferenceSystem.operation: src/core/proj/qgscoordinatereferencesystem.h#L854 +QgsCoordinateReferenceSystem.postgisSrid: src/core/proj/qgscoordinatereferencesystem.h#L639 +QgsCoordinateReferenceSystem.projectionAcronym: src/core/proj/qgscoordinatereferencesystem.h#L685 +QgsCoordinateReferenceSystem.pushRecentCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L1131 +QgsCoordinateReferenceSystem.readXml: src/core/proj/qgscoordinatereferencesystem.h#L602 +QgsCoordinateReferenceSystem.recentProjections: src/core/proj/qgscoordinatereferencesystem.h#L1117 +QgsCoordinateReferenceSystem.removeRecentCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L1138 +QgsCoordinateReferenceSystem.saveAsUserCrs: src/core/proj/qgscoordinatereferencesystem.h#L993 +QgsCoordinateReferenceSystem.setCoordinateEpoch: src/core/proj/qgscoordinatereferencesystem.h#L808 +QgsCoordinateReferenceSystem.setNativeFormat: src/core/proj/qgscoordinatereferencesystem.h#L1004 +QgsCoordinateReferenceSystem.setValidationHint: src/core/proj/qgscoordinatereferencesystem.h#L965 +QgsCoordinateReferenceSystem.setupESRIWktFix: src/core/proj/qgscoordinatereferencesystem.h#L562 +QgsCoordinateReferenceSystem.srsid: src/core/proj/qgscoordinatereferencesystem.h#L631 +QgsCoordinateReferenceSystem.syncDatabase: src/core/proj/qgscoordinatereferencesystem.h#L978 +QgsCoordinateReferenceSystem.toGeographicCrs: src/core/proj/qgscoordinatereferencesystem.h#L1026 +QgsCoordinateReferenceSystem.toOgcUri: src/core/proj/qgscoordinatereferencesystem.h#L932 +QgsCoordinateReferenceSystem.toOgcUrn: src/core/proj/qgscoordinatereferencesystem.h#L940 +QgsCoordinateReferenceSystem.toProj4: src/core/proj/qgscoordinatereferencesystem.h#L720 +QgsCoordinateReferenceSystem.toProj: src/core/proj/qgscoordinatereferencesystem.h#L734 +QgsCoordinateReferenceSystem.toWkt: src/core/proj/qgscoordinatereferencesystem.h#L706 +QgsCoordinateReferenceSystem.type: src/core/proj/qgscoordinatereferencesystem.h#L741 +QgsCoordinateReferenceSystem.updateDefinition: src/core/proj/qgscoordinatereferencesystem.h#L960 +QgsCoordinateReferenceSystem.userFriendlyIdentifier: src/core/proj/qgscoordinatereferencesystem.h#L677 +QgsCoordinateReferenceSystem.validate: src/core/proj/qgscoordinatereferencesystem.h#L579 +QgsCoordinateReferenceSystem.validationHint: src/core/proj/qgscoordinatereferencesystem.h#L970 +QgsCoordinateReferenceSystem.verticalCrs: src/core/proj/qgscoordinatereferencesystem.h#L1052 +QgsCoordinateReferenceSystem.writeXml: src/core/proj/qgscoordinatereferencesystem.h#L610 +QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L206 QgsCoordinateReferenceSystemRegistry.QgsCoordinateReferenceSystemRegistry: src/core/proj/qgscoordinatereferencesystemregistry.h#L72 QgsCoordinateReferenceSystemRegistry.UserCrsDetails: src/core/proj/qgscoordinatereferencesystemregistry.h#L81 QgsCoordinateReferenceSystemRegistry.addUserCrs: src/core/proj/qgscoordinatereferencesystemregistry.h#L124 -QgsCoordinateReferenceSystemRegistry.clearRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L222 -QgsCoordinateReferenceSystemRegistry.crsDefinitionsChanged: src/core/proj/qgscoordinatereferencesystemregistry.h#L262 -QgsCoordinateReferenceSystemRegistry.pushRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L204 -QgsCoordinateReferenceSystemRegistry.recentCrsCleared: src/core/proj/qgscoordinatereferencesystemregistry.h#L289 -QgsCoordinateReferenceSystemRegistry.recentCrsPushed: src/core/proj/qgscoordinatereferencesystemregistry.h#L271 -QgsCoordinateReferenceSystemRegistry.recentCrsRemoved: src/core/proj/qgscoordinatereferencesystemregistry.h#L280 -QgsCoordinateReferenceSystemRegistry.removeRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L213 +QgsCoordinateReferenceSystemRegistry.clearRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L218 +QgsCoordinateReferenceSystemRegistry.crsDefinitionsChanged: src/core/proj/qgscoordinatereferencesystemregistry.h#L258 +QgsCoordinateReferenceSystemRegistry.pushRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L200 +QgsCoordinateReferenceSystemRegistry.recentCrsCleared: src/core/proj/qgscoordinatereferencesystemregistry.h#L285 +QgsCoordinateReferenceSystemRegistry.recentCrsPushed: src/core/proj/qgscoordinatereferencesystemregistry.h#L267 +QgsCoordinateReferenceSystemRegistry.recentCrsRemoved: src/core/proj/qgscoordinatereferencesystemregistry.h#L276 +QgsCoordinateReferenceSystemRegistry.removeRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L209 QgsCoordinateReferenceSystemRegistry.removeUserCrs: src/core/proj/qgscoordinatereferencesystemregistry.h#L151 QgsCoordinateReferenceSystemRegistry.updateUserCrs: src/core/proj/qgscoordinatereferencesystemregistry.h#L142 -QgsCoordinateReferenceSystemRegistry.userCrsAdded: src/core/proj/qgscoordinatereferencesystemregistry.h#L248 -QgsCoordinateReferenceSystemRegistry.userCrsChanged: src/core/proj/qgscoordinatereferencesystemregistry.h#L238 -QgsCoordinateReferenceSystemRegistry.userCrsRemoved: src/core/proj/qgscoordinatereferencesystemregistry.h#L256 +QgsCoordinateReferenceSystemRegistry.userCrsAdded: src/core/proj/qgscoordinatereferencesystemregistry.h#L244 +QgsCoordinateReferenceSystemRegistry.userCrsChanged: src/core/proj/qgscoordinatereferencesystemregistry.h#L234 +QgsCoordinateReferenceSystemRegistry.userCrsRemoved: src/core/proj/qgscoordinatereferencesystemregistry.h#L252 QgsCoordinateReferenceSystemRegistry: src/core/proj/qgscoordinatereferencesystemregistry.h#L64 QgsCoordinateReferenceSystemUtils.axisDirectionToAbbreviatedString: src/core/proj/qgscoordinatereferencesystemutils.h#L47 QgsCoordinateReferenceSystemUtils.crsTypeToString: src/core/proj/qgscoordinatereferencesystemutils.h#L53 diff --git a/python/core/class_map.yaml b/python/core/class_map.yaml index 47d7d71081b87..6b80f2477c201 100644 --- a/python/core/class_map.yaml +++ b/python/core/class_map.yaml @@ -2620,91 +2620,91 @@ QgsCoordinateFormatter.formatX: src/core/qgscoordinateformatter.h#L75 QgsCoordinateFormatter.formatY: src/core/qgscoordinateformatter.h#L88 QgsCoordinateFormatter.separator: src/core/qgscoordinateformatter.h#L116 QgsCoordinateFormatter: src/core/qgscoordinateformatter.h#L39 -QgsCoordinateReferenceSystem.QVariant: src/core/proj/qgscoordinatereferencesystem.h#L280 -QgsCoordinateReferenceSystem.QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L256 -QgsCoordinateReferenceSystem.QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L271 -QgsCoordinateReferenceSystem.__repr__: src/core/proj/qgscoordinatereferencesystem.h#L1079 -QgsCoordinateReferenceSystem.authid: src/core/proj/qgscoordinatereferencesystem.h#L658 -QgsCoordinateReferenceSystem.axisOrdering: src/core/proj/qgscoordinatereferencesystem.h#L886 -QgsCoordinateReferenceSystem.bounds: src/core/proj/qgscoordinatereferencesystem.h#L937 -QgsCoordinateReferenceSystem.celestialBodyName: src/core/proj/qgscoordinatereferencesystem.h#L796 -QgsCoordinateReferenceSystem.clearRecentCoordinateReferenceSystems: src/core/proj/qgscoordinatereferencesystem.h#L1158 -QgsCoordinateReferenceSystem.coordinateEpoch: src/core/proj/qgscoordinatereferencesystem.h#L846 -QgsCoordinateReferenceSystem.createCompoundCrs: src/core/proj/qgscoordinatereferencesystem.h#L376 -QgsCoordinateReferenceSystem.createFromId: src/core/proj/qgscoordinatereferencesystem.h#L387 -QgsCoordinateReferenceSystem.createFromOgcWmsCrs: src/core/proj/qgscoordinatereferencesystem.h#L404 -QgsCoordinateReferenceSystem.createFromProj4: src/core/proj/qgscoordinatereferencesystem.h#L477 -QgsCoordinateReferenceSystem.createFromProj: src/core/proj/qgscoordinatereferencesystem.h#L511 -QgsCoordinateReferenceSystem.createFromSrid: src/core/proj/qgscoordinatereferencesystem.h#L415 -QgsCoordinateReferenceSystem.createFromSrsId: src/core/proj/qgscoordinatereferencesystem.h#L449 -QgsCoordinateReferenceSystem.createFromString: src/core/proj/qgscoordinatereferencesystem.h#L533 -QgsCoordinateReferenceSystem.createFromUserInput: src/core/proj/qgscoordinatereferencesystem.h#L555 -QgsCoordinateReferenceSystem.createFromWkt: src/core/proj/qgscoordinatereferencesystem.h#L432 -QgsCoordinateReferenceSystem.datumEnsemble: src/core/proj/qgscoordinatereferencesystem.h#L785 -QgsCoordinateReferenceSystem.description: src/core/proj/qgscoordinatereferencesystem.h#L667 -QgsCoordinateReferenceSystem.ellipsoidAcronym: src/core/proj/qgscoordinatereferencesystem.h#L698 -QgsCoordinateReferenceSystem.factors: src/core/proj/qgscoordinatereferencesystem.h#L859 -QgsCoordinateReferenceSystem.findMatchingProj: src/core/proj/qgscoordinatereferencesystem.h#L596 -QgsCoordinateReferenceSystem.fromEpsgId: src/core/proj/qgscoordinatereferencesystem.h#L313 -QgsCoordinateReferenceSystem.fromOgcWmsCrs: src/core/proj/qgscoordinatereferencesystem.h#L302 -QgsCoordinateReferenceSystem.fromProj4: src/core/proj/qgscoordinatereferencesystem.h#L325 -QgsCoordinateReferenceSystem.fromProj: src/core/proj/qgscoordinatereferencesystem.h#L334 -QgsCoordinateReferenceSystem.fromSrsId: src/core/proj/qgscoordinatereferencesystem.h#L359 -QgsCoordinateReferenceSystem.fromWkt: src/core/proj/qgscoordinatereferencesystem.h#L346 -QgsCoordinateReferenceSystem.geographicCrsAuthId: src/core/proj/qgscoordinatereferencesystem.h#L1076 -QgsCoordinateReferenceSystem.hasAxisInverted: src/core/proj/qgscoordinatereferencesystem.h#L876 -QgsCoordinateReferenceSystem.hasVerticalAxis: src/core/proj/qgscoordinatereferencesystem.h#L1073 -QgsCoordinateReferenceSystem.horizontalCrs: src/core/proj/qgscoordinatereferencesystem.h#L1051 -QgsCoordinateReferenceSystem.invalidateCache: src/core/proj/qgscoordinatereferencesystem.h#L1180 -QgsCoordinateReferenceSystem.isDeprecated: src/core/proj/qgscoordinatereferencesystem.h#L753 -QgsCoordinateReferenceSystem.isDynamic: src/core/proj/qgscoordinatereferencesystem.h#L769 -QgsCoordinateReferenceSystem.isGeographic: src/core/proj/qgscoordinatereferencesystem.h#L759 -QgsCoordinateReferenceSystem.isValid: src/core/proj/qgscoordinatereferencesystem.h#L570 -QgsCoordinateReferenceSystem.mapUnits: src/core/proj/qgscoordinatereferencesystem.h#L928 -QgsCoordinateReferenceSystem.nativeFormat: src/core/proj/qgscoordinatereferencesystem.h#L1028 -QgsCoordinateReferenceSystem.operation: src/core/proj/qgscoordinatereferencesystem.h#L867 -QgsCoordinateReferenceSystem.postgisSrid: src/core/proj/qgscoordinatereferencesystem.h#L644 -QgsCoordinateReferenceSystem.projectionAcronym: src/core/proj/qgscoordinatereferencesystem.h#L690 -QgsCoordinateReferenceSystem.pushRecentCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L1144 -QgsCoordinateReferenceSystem.readXml: src/core/proj/qgscoordinatereferencesystem.h#L607 -QgsCoordinateReferenceSystem.recentProjections: src/core/proj/qgscoordinatereferencesystem.h#L1130 -QgsCoordinateReferenceSystem.removeRecentCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L1151 -QgsCoordinateReferenceSystem.saveAsUserCrs: src/core/proj/qgscoordinatereferencesystem.h#L1006 -QgsCoordinateReferenceSystem.setCoordinateEpoch: src/core/proj/qgscoordinatereferencesystem.h#L821 -QgsCoordinateReferenceSystem.setNativeFormat: src/core/proj/qgscoordinatereferencesystem.h#L1017 -QgsCoordinateReferenceSystem.setValidationHint: src/core/proj/qgscoordinatereferencesystem.h#L978 -QgsCoordinateReferenceSystem.setupESRIWktFix: src/core/proj/qgscoordinatereferencesystem.h#L567 -QgsCoordinateReferenceSystem.srsid: src/core/proj/qgscoordinatereferencesystem.h#L636 -QgsCoordinateReferenceSystem.syncDatabase: src/core/proj/qgscoordinatereferencesystem.h#L991 -QgsCoordinateReferenceSystem.toGeographicCrs: src/core/proj/qgscoordinatereferencesystem.h#L1039 -QgsCoordinateReferenceSystem.toOgcUri: src/core/proj/qgscoordinatereferencesystem.h#L945 -QgsCoordinateReferenceSystem.toOgcUrn: src/core/proj/qgscoordinatereferencesystem.h#L953 -QgsCoordinateReferenceSystem.toProj4: src/core/proj/qgscoordinatereferencesystem.h#L725 -QgsCoordinateReferenceSystem.toProj: src/core/proj/qgscoordinatereferencesystem.h#L739 -QgsCoordinateReferenceSystem.toWkt: src/core/proj/qgscoordinatereferencesystem.h#L711 -QgsCoordinateReferenceSystem.type: src/core/proj/qgscoordinatereferencesystem.h#L746 -QgsCoordinateReferenceSystem.updateDefinition: src/core/proj/qgscoordinatereferencesystem.h#L973 -QgsCoordinateReferenceSystem.userFriendlyIdentifier: src/core/proj/qgscoordinatereferencesystem.h#L682 -QgsCoordinateReferenceSystem.validate: src/core/proj/qgscoordinatereferencesystem.h#L584 -QgsCoordinateReferenceSystem.validationHint: src/core/proj/qgscoordinatereferencesystem.h#L983 -QgsCoordinateReferenceSystem.verticalCrs: src/core/proj/qgscoordinatereferencesystem.h#L1065 -QgsCoordinateReferenceSystem.writeXml: src/core/proj/qgscoordinatereferencesystem.h#L615 -QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L211 +QgsCoordinateReferenceSystem.QVariant: src/core/proj/qgscoordinatereferencesystem.h#L275 +QgsCoordinateReferenceSystem.QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L251 +QgsCoordinateReferenceSystem.QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L266 +QgsCoordinateReferenceSystem.__repr__: src/core/proj/qgscoordinatereferencesystem.h#L1066 +QgsCoordinateReferenceSystem.authid: src/core/proj/qgscoordinatereferencesystem.h#L653 +QgsCoordinateReferenceSystem.axisOrdering: src/core/proj/qgscoordinatereferencesystem.h#L873 +QgsCoordinateReferenceSystem.bounds: src/core/proj/qgscoordinatereferencesystem.h#L924 +QgsCoordinateReferenceSystem.celestialBodyName: src/core/proj/qgscoordinatereferencesystem.h#L783 +QgsCoordinateReferenceSystem.clearRecentCoordinateReferenceSystems: src/core/proj/qgscoordinatereferencesystem.h#L1145 +QgsCoordinateReferenceSystem.coordinateEpoch: src/core/proj/qgscoordinatereferencesystem.h#L833 +QgsCoordinateReferenceSystem.createCompoundCrs: src/core/proj/qgscoordinatereferencesystem.h#L371 +QgsCoordinateReferenceSystem.createFromId: src/core/proj/qgscoordinatereferencesystem.h#L382 +QgsCoordinateReferenceSystem.createFromOgcWmsCrs: src/core/proj/qgscoordinatereferencesystem.h#L399 +QgsCoordinateReferenceSystem.createFromProj4: src/core/proj/qgscoordinatereferencesystem.h#L472 +QgsCoordinateReferenceSystem.createFromProj: src/core/proj/qgscoordinatereferencesystem.h#L506 +QgsCoordinateReferenceSystem.createFromSrid: src/core/proj/qgscoordinatereferencesystem.h#L410 +QgsCoordinateReferenceSystem.createFromSrsId: src/core/proj/qgscoordinatereferencesystem.h#L444 +QgsCoordinateReferenceSystem.createFromString: src/core/proj/qgscoordinatereferencesystem.h#L528 +QgsCoordinateReferenceSystem.createFromUserInput: src/core/proj/qgscoordinatereferencesystem.h#L550 +QgsCoordinateReferenceSystem.createFromWkt: src/core/proj/qgscoordinatereferencesystem.h#L427 +QgsCoordinateReferenceSystem.datumEnsemble: src/core/proj/qgscoordinatereferencesystem.h#L776 +QgsCoordinateReferenceSystem.description: src/core/proj/qgscoordinatereferencesystem.h#L662 +QgsCoordinateReferenceSystem.ellipsoidAcronym: src/core/proj/qgscoordinatereferencesystem.h#L693 +QgsCoordinateReferenceSystem.factors: src/core/proj/qgscoordinatereferencesystem.h#L846 +QgsCoordinateReferenceSystem.findMatchingProj: src/core/proj/qgscoordinatereferencesystem.h#L591 +QgsCoordinateReferenceSystem.fromEpsgId: src/core/proj/qgscoordinatereferencesystem.h#L308 +QgsCoordinateReferenceSystem.fromOgcWmsCrs: src/core/proj/qgscoordinatereferencesystem.h#L297 +QgsCoordinateReferenceSystem.fromProj4: src/core/proj/qgscoordinatereferencesystem.h#L320 +QgsCoordinateReferenceSystem.fromProj: src/core/proj/qgscoordinatereferencesystem.h#L329 +QgsCoordinateReferenceSystem.fromSrsId: src/core/proj/qgscoordinatereferencesystem.h#L354 +QgsCoordinateReferenceSystem.fromWkt: src/core/proj/qgscoordinatereferencesystem.h#L341 +QgsCoordinateReferenceSystem.geographicCrsAuthId: src/core/proj/qgscoordinatereferencesystem.h#L1063 +QgsCoordinateReferenceSystem.hasAxisInverted: src/core/proj/qgscoordinatereferencesystem.h#L863 +QgsCoordinateReferenceSystem.hasVerticalAxis: src/core/proj/qgscoordinatereferencesystem.h#L1060 +QgsCoordinateReferenceSystem.horizontalCrs: src/core/proj/qgscoordinatereferencesystem.h#L1038 +QgsCoordinateReferenceSystem.invalidateCache: src/core/proj/qgscoordinatereferencesystem.h#L1167 +QgsCoordinateReferenceSystem.isDeprecated: src/core/proj/qgscoordinatereferencesystem.h#L748 +QgsCoordinateReferenceSystem.isDynamic: src/core/proj/qgscoordinatereferencesystem.h#L764 +QgsCoordinateReferenceSystem.isGeographic: src/core/proj/qgscoordinatereferencesystem.h#L754 +QgsCoordinateReferenceSystem.isValid: src/core/proj/qgscoordinatereferencesystem.h#L565 +QgsCoordinateReferenceSystem.mapUnits: src/core/proj/qgscoordinatereferencesystem.h#L915 +QgsCoordinateReferenceSystem.nativeFormat: src/core/proj/qgscoordinatereferencesystem.h#L1015 +QgsCoordinateReferenceSystem.operation: src/core/proj/qgscoordinatereferencesystem.h#L854 +QgsCoordinateReferenceSystem.postgisSrid: src/core/proj/qgscoordinatereferencesystem.h#L639 +QgsCoordinateReferenceSystem.projectionAcronym: src/core/proj/qgscoordinatereferencesystem.h#L685 +QgsCoordinateReferenceSystem.pushRecentCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L1131 +QgsCoordinateReferenceSystem.readXml: src/core/proj/qgscoordinatereferencesystem.h#L602 +QgsCoordinateReferenceSystem.recentProjections: src/core/proj/qgscoordinatereferencesystem.h#L1117 +QgsCoordinateReferenceSystem.removeRecentCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L1138 +QgsCoordinateReferenceSystem.saveAsUserCrs: src/core/proj/qgscoordinatereferencesystem.h#L993 +QgsCoordinateReferenceSystem.setCoordinateEpoch: src/core/proj/qgscoordinatereferencesystem.h#L808 +QgsCoordinateReferenceSystem.setNativeFormat: src/core/proj/qgscoordinatereferencesystem.h#L1004 +QgsCoordinateReferenceSystem.setValidationHint: src/core/proj/qgscoordinatereferencesystem.h#L965 +QgsCoordinateReferenceSystem.setupESRIWktFix: src/core/proj/qgscoordinatereferencesystem.h#L562 +QgsCoordinateReferenceSystem.srsid: src/core/proj/qgscoordinatereferencesystem.h#L631 +QgsCoordinateReferenceSystem.syncDatabase: src/core/proj/qgscoordinatereferencesystem.h#L978 +QgsCoordinateReferenceSystem.toGeographicCrs: src/core/proj/qgscoordinatereferencesystem.h#L1026 +QgsCoordinateReferenceSystem.toOgcUri: src/core/proj/qgscoordinatereferencesystem.h#L932 +QgsCoordinateReferenceSystem.toOgcUrn: src/core/proj/qgscoordinatereferencesystem.h#L940 +QgsCoordinateReferenceSystem.toProj4: src/core/proj/qgscoordinatereferencesystem.h#L720 +QgsCoordinateReferenceSystem.toProj: src/core/proj/qgscoordinatereferencesystem.h#L734 +QgsCoordinateReferenceSystem.toWkt: src/core/proj/qgscoordinatereferencesystem.h#L706 +QgsCoordinateReferenceSystem.type: src/core/proj/qgscoordinatereferencesystem.h#L741 +QgsCoordinateReferenceSystem.updateDefinition: src/core/proj/qgscoordinatereferencesystem.h#L960 +QgsCoordinateReferenceSystem.userFriendlyIdentifier: src/core/proj/qgscoordinatereferencesystem.h#L677 +QgsCoordinateReferenceSystem.validate: src/core/proj/qgscoordinatereferencesystem.h#L579 +QgsCoordinateReferenceSystem.validationHint: src/core/proj/qgscoordinatereferencesystem.h#L970 +QgsCoordinateReferenceSystem.verticalCrs: src/core/proj/qgscoordinatereferencesystem.h#L1052 +QgsCoordinateReferenceSystem.writeXml: src/core/proj/qgscoordinatereferencesystem.h#L610 +QgsCoordinateReferenceSystem: src/core/proj/qgscoordinatereferencesystem.h#L206 QgsCoordinateReferenceSystemRegistry.QgsCoordinateReferenceSystemRegistry: src/core/proj/qgscoordinatereferencesystemregistry.h#L72 QgsCoordinateReferenceSystemRegistry.UserCrsDetails: src/core/proj/qgscoordinatereferencesystemregistry.h#L81 QgsCoordinateReferenceSystemRegistry.addUserCrs: src/core/proj/qgscoordinatereferencesystemregistry.h#L124 -QgsCoordinateReferenceSystemRegistry.clearRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L222 -QgsCoordinateReferenceSystemRegistry.crsDefinitionsChanged: src/core/proj/qgscoordinatereferencesystemregistry.h#L262 -QgsCoordinateReferenceSystemRegistry.pushRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L204 -QgsCoordinateReferenceSystemRegistry.recentCrsCleared: src/core/proj/qgscoordinatereferencesystemregistry.h#L289 -QgsCoordinateReferenceSystemRegistry.recentCrsPushed: src/core/proj/qgscoordinatereferencesystemregistry.h#L271 -QgsCoordinateReferenceSystemRegistry.recentCrsRemoved: src/core/proj/qgscoordinatereferencesystemregistry.h#L280 -QgsCoordinateReferenceSystemRegistry.removeRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L213 +QgsCoordinateReferenceSystemRegistry.clearRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L218 +QgsCoordinateReferenceSystemRegistry.crsDefinitionsChanged: src/core/proj/qgscoordinatereferencesystemregistry.h#L258 +QgsCoordinateReferenceSystemRegistry.pushRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L200 +QgsCoordinateReferenceSystemRegistry.recentCrsCleared: src/core/proj/qgscoordinatereferencesystemregistry.h#L285 +QgsCoordinateReferenceSystemRegistry.recentCrsPushed: src/core/proj/qgscoordinatereferencesystemregistry.h#L267 +QgsCoordinateReferenceSystemRegistry.recentCrsRemoved: src/core/proj/qgscoordinatereferencesystemregistry.h#L276 +QgsCoordinateReferenceSystemRegistry.removeRecent: src/core/proj/qgscoordinatereferencesystemregistry.h#L209 QgsCoordinateReferenceSystemRegistry.removeUserCrs: src/core/proj/qgscoordinatereferencesystemregistry.h#L151 QgsCoordinateReferenceSystemRegistry.updateUserCrs: src/core/proj/qgscoordinatereferencesystemregistry.h#L142 -QgsCoordinateReferenceSystemRegistry.userCrsAdded: src/core/proj/qgscoordinatereferencesystemregistry.h#L248 -QgsCoordinateReferenceSystemRegistry.userCrsChanged: src/core/proj/qgscoordinatereferencesystemregistry.h#L238 -QgsCoordinateReferenceSystemRegistry.userCrsRemoved: src/core/proj/qgscoordinatereferencesystemregistry.h#L256 +QgsCoordinateReferenceSystemRegistry.userCrsAdded: src/core/proj/qgscoordinatereferencesystemregistry.h#L244 +QgsCoordinateReferenceSystemRegistry.userCrsChanged: src/core/proj/qgscoordinatereferencesystemregistry.h#L234 +QgsCoordinateReferenceSystemRegistry.userCrsRemoved: src/core/proj/qgscoordinatereferencesystemregistry.h#L252 QgsCoordinateReferenceSystemRegistry: src/core/proj/qgscoordinatereferencesystemregistry.h#L64 QgsCoordinateReferenceSystemUtils.axisDirectionToAbbreviatedString: src/core/proj/qgscoordinatereferencesystemutils.h#L47 QgsCoordinateReferenceSystemUtils.crsTypeToString: src/core/proj/qgscoordinatereferencesystemutils.h#L53 From 176890fcf54d208858cd29c9f741d7d22c39aa8a Mon Sep 17 00:00:00 2001 From: Julien Cabieces Date: Thu, 30 Jan 2025 18:08:42 +0100 Subject: [PATCH 40/81] fix(SipDeprecated): Don't use deprecated annotation with message It crashes in 6.9.1 --- cmake/SIPMacros.cmake | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cmake/SIPMacros.cmake b/cmake/SIPMacros.cmake index e69e208b6a104..2f44b71c7befa 100644 --- a/cmake/SIPMacros.cmake +++ b/cmake/SIPMacros.cmake @@ -65,11 +65,14 @@ MACRO(GENERATE_SIP_PYTHON_MODULE_CODE MODULE_NAME MODULE_SIP SIP_FILES CPP_FILES CONFIGURE_FILE(${_sip_file} ${_out_sip_file}) # Deprecated annotation supports message only since version 6.9.0 - if(${SIP_VERSION_STR} VERSION_LESS 6.9.0) - file(READ ${_out_sip_file} _content) - string(REGEX REPLACE "([/,])Deprecated=\"[^\"]*\"([/,])" "\\1Deprecated\\2" _content "${_content}") - file(GENERATE OUTPUT ${_out_sip_file} CONTENT "${_content}") - endif() + # if(${SIP_VERSION_STR} VERSION_LESS 6.9.0) + + # For now disabling SIP deprecated because it crashes the application + file(READ ${_out_sip_file} _content) + string(REGEX REPLACE "([/,])Deprecated=\"[^\"]*\"([/,])" "\\1Deprecated\\2" _content "${_content}") + file(GENERATE OUTPUT ${_out_sip_file} CONTENT "${_content}") + + # endif() ENDFOREACH (_sip_file) From 6dae454943eee7b344484ff26ecc6398112b498a Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Wed, 29 Jan 2025 14:44:01 +0000 Subject: [PATCH 41/81] add raster creation options support to georeferencer (fix #47362) --- src/app/georeferencer/qgsgeorefmainwindow.cpp | 23 ++- src/app/georeferencer/qgsgeorefmainwindow.h | 7 +- src/app/georeferencer/qgsimagewarper.cpp | 157 +++++++++++++++++- src/app/georeferencer/qgsimagewarper.h | 24 ++- .../qgstransformsettingsdialog.cpp | 21 ++- .../qgstransformsettingsdialog.h | 8 +- .../qgstransformsettingsdialogbase.ui | 114 ++++++------- 7 files changed, 266 insertions(+), 88 deletions(-) diff --git a/src/app/georeferencer/qgsgeorefmainwindow.cpp b/src/app/georeferencer/qgsgeorefmainwindow.cpp index a03fd0d0ec780..ef15e84cf7642 100644 --- a/src/app/georeferencer/qgsgeorefmainwindow.cpp +++ b/src/app/georeferencer/qgsgeorefmainwindow.cpp @@ -78,7 +78,7 @@ const QgsSettingsEntryEnumFlag *QgsGeoreferencerMainWindow::settingResamplingMethod = new QgsSettingsEntryEnumFlag( QStringLiteral( "resampling-method" ), sTreeGeoreferencer, QgsImageWarper::ResamplingMethod::NearestNeighbour, QObject::tr( "Last used georeferencer resampling method" ) ); -const QgsSettingsEntryString *QgsGeoreferencerMainWindow::settingCompressionMethod = new QgsSettingsEntryString( QStringLiteral( "compression-method" ), sTreeGeoreferencer, QStringLiteral( "NONE" ), QObject::tr( "Last used georeferencer compression method" ) ); +const QgsSettingsEntryStringList *QgsGeoreferencerMainWindow::settingCreationOptions = new QgsSettingsEntryStringList( QStringLiteral( "creation-options" ), sTreeGeoreferencer, QStringList(), QObject::tr( "Last used georeferencer raster creation options" ) ); const QgsSettingsEntryBool *QgsGeoreferencerMainWindow::settingUseZeroForTransparent = new QgsSettingsEntryBool( QStringLiteral( "use-zero-for-transparent" ), sTreeGeoreferencer, false, QObject::tr( "Last used georeferencer use-zero-as-transparent option" ) ); @@ -454,7 +454,7 @@ bool QgsGeoreferencerMainWindow::showTransformSettingsDialog() d.setCreateWorldFileOnly( mCreateWorldFileOnly ); d.setTransformMethod( mTransformMethod ); d.setResamplingMethod( mResamplingMethod ); - d.setCompressionMethod( mCompressionMethod ); + d.setCreationOptions( mCreationOptions.join( ' ' ) ); d.setPdfMapFilename( mPdfOutputMapFile ); d.setPdfReportFilename( mPdfOutputFile ); d.setSaveGcpPoints( mSaveGcp ); @@ -472,7 +472,7 @@ bool QgsGeoreferencerMainWindow::showTransformSettingsDialog() mTargetCrs = d.targetCrs(); mTransformMethod = d.transformMethod(); mResamplingMethod = d.resamplingMethod(); - mCompressionMethod = d.compressionMethod(); + mCreationOptions = d.creationOptions(); mModifiedFileName = d.destinationFilename(); mPdfOutputMapFile = d.pdfMapFilename(); mPdfOutputFile = d.pdfReportFilename(); @@ -534,7 +534,7 @@ void QgsGeoreferencerMainWindow::generateGDALScript() int order = polynomialOrder( mTransformMethod ); if ( order != 0 ) { - gdalwarpCommand = generateGDALwarpCommand( resamplingStr, mCompressionMethod, mUseZeroForTrans, order, mUserResX, mUserResY ); + gdalwarpCommand = generateGDALwarpCommand( resamplingStr, mCreationOptions, mUseZeroForTrans, order, mUserResX, mUserResY ); showGDALScript( QStringList() << translateCommand << gdalwarpCommand ); } else @@ -1440,7 +1440,7 @@ void QgsGeoreferencerMainWindow::readSettings() // warp options mResamplingMethod = settingResamplingMethod->value(); - mCompressionMethod = settingCompressionMethod->value(); + mCreationOptions = settingCreationOptions->value(); mUseZeroForTrans = settingUseZeroForTransparent->value(); mTransformMethod = settingTransformMethod->value(); mSaveGcp = settingSaveGcps->value(); @@ -1455,7 +1455,7 @@ void QgsGeoreferencerMainWindow::writeSettings() settingTransformMethod->setValue( mTransformMethod ); settingResamplingMethod->setValue( mResamplingMethod ); - settingCompressionMethod->setValue( mCompressionMethod ); + settingCreationOptions->setValue( mCreationOptions ); settingUseZeroForTransparent->setValue( mUseZeroForTrans ); settingSaveGcps->setValue( mSaveGcp ); settingLoadInProject->setValue( mLoadInQgis ); @@ -1597,7 +1597,7 @@ bool QgsGeoreferencerMainWindow::georeferenceRaster() mGeorefTransform, mResamplingMethod, mUseZeroForTrans, - mCompressionMethod, + mCreationOptions, mTargetCrs, mUserResX, mUserResY @@ -2267,7 +2267,7 @@ QString QgsGeoreferencerMainWindow::generateGDALogr2ogrCommand() const return gdalCommand.join( QLatin1Char( ' ' ) ); } -QString QgsGeoreferencerMainWindow::generateGDALwarpCommand( const QString &resampling, const QString &compress, bool useZeroForTrans, int order, double targetResX, double targetResY ) +QString QgsGeoreferencerMainWindow::generateGDALwarpCommand( const QString &resampling, const QStringList &options, bool useZeroForTrans, int order, double targetResX, double targetResY ) { QStringList gdalCommand; gdalCommand << QStringLiteral( "gdalwarp" ) << QStringLiteral( "-r" ) << resampling; @@ -2282,7 +2282,12 @@ QString QgsGeoreferencerMainWindow::generateGDALwarpCommand( const QString &resa // Otherwise, use thin plate spline interpolation gdalCommand << QStringLiteral( "-tps" ); } - gdalCommand << "-co COMPRESS=" + compress << ( useZeroForTrans ? "-dstalpha" : "" ); + + for ( const QString &option : options ) + { + gdalCommand << QStringLiteral( "-co %1" ).arg( option ); + } + gdalCommand << ( useZeroForTrans ? "-dstalpha" : "" ); if ( targetResX != 0.0 && targetResY != 0.0 ) { diff --git a/src/app/georeferencer/qgsgeorefmainwindow.h b/src/app/georeferencer/qgsgeorefmainwindow.h index fda7bee22a22b..0998f2b5b5890 100644 --- a/src/app/georeferencer/qgsgeorefmainwindow.h +++ b/src/app/georeferencer/qgsgeorefmainwindow.h @@ -52,6 +52,7 @@ class QgsMapLayer; class QgsScreenHelper; class QgsSettingsEntryBool; class QgsSettingsEntryString; +class QgsSettingsEntryStringList; template class QgsSettingsEntryEnumFlag; @@ -70,7 +71,7 @@ class APP_EXPORT QgsGeoreferencerMainWindow : public QMainWindow, private Ui::Qg static inline QgsSettingsTreeNode *sTreeGeoreferencer = QgsSettingsTree::sTreeApp->createChildNode( QStringLiteral( "georeferencer" ) ); static const QgsSettingsEntryEnumFlag *settingResamplingMethod; - static const QgsSettingsEntryString *settingCompressionMethod; + static const QgsSettingsEntryStringList *settingCreationOptions; static const QgsSettingsEntryBool *settingUseZeroForTransparent; static const QgsSettingsEntryEnumFlag *settingTransformMethod; static const QgsSettingsEntryBool *settingSaveGcps; @@ -208,7 +209,7 @@ class APP_EXPORT QgsGeoreferencerMainWindow : public QMainWindow, private Ui::Qg * For values in the range 1 to 3, the parameter "order" prescribes the degree of the interpolating polynomials to use, * a value of -1 indicates that thin plate spline interpolation should be used for warping. */ - QString generateGDALwarpCommand( const QString &resampling, const QString &compress, bool useZeroForTrans, int order, double targetResX, double targetResY ); + QString generateGDALwarpCommand( const QString &resampling, const QStringList &options, bool useZeroForTrans, int order, double targetResX, double targetResY ); // utils bool validate(); @@ -268,7 +269,7 @@ class APP_EXPORT QgsGeoreferencerMainWindow : public QMainWindow, private Ui::Qg QgsGcpTransformerInterface::TransformMethod mTransformMethod = QgsGcpTransformerInterface::TransformMethod::InvalidTransform; QgsImageWarper::ResamplingMethod mResamplingMethod; QgsGeorefTransform mGeorefTransform; - QString mCompressionMethod = QStringLiteral( "NONE" ); + QStringList mCreationOptions; bool mCreateWorldFileOnly = false; QgsGCPList mPoints; diff --git a/src/app/georeferencer/qgsimagewarper.cpp b/src/app/georeferencer/qgsimagewarper.cpp index a88c9dc517682..491c444b6b1ae 100644 --- a/src/app/georeferencer/qgsimagewarper.cpp +++ b/src/app/georeferencer/qgsimagewarper.cpp @@ -123,6 +123,72 @@ bool QgsImageWarper::createDestinationDataset( const QString &outputName, GDALDa return true; } +bool QgsImageWarper::createDestinationDataset( const QString &outputName, GDALDatasetH hSrcDS, gdal::dataset_unique_ptr &hDstDS, uint resX, uint resY, double *adfGeoTransform, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs ) +{ + // create the output file + GDALDriverH driver = GDALGetDriverByName( "GTiff" ); + if ( !driver ) + { + return false; + } + char **papszOptions = nullptr; + for ( const QString &option : options ) + { + QStringList tokens = option.split( '=', Qt::SkipEmptyParts ); + papszOptions = CSLSetNameValue( papszOptions, tokens.at( 0 ).toUtf8().constData(), tokens.at( 1 ).toUtf8().constData() ); + } + hDstDS.reset( GDALCreate( driver, outputName.toUtf8().constData(), resX, resY, GDALGetRasterCount( hSrcDS ), GDALGetRasterDataType( GDALGetRasterBand( hSrcDS, 1 ) ), papszOptions ) ); + if ( !hDstDS ) + { + return false; + } + + if ( CE_None != GDALSetGeoTransform( hDstDS.get(), adfGeoTransform ) ) + { + return false; + } + + if ( crs.isValid() ) + { + OGRSpatialReference oTargetSRS; + oTargetSRS.importFromWkt( crs.toWkt( Qgis::CrsWktVariant::PreferredGdal ).toUtf8().data() ); + + char *wkt = nullptr; + const OGRErr err = oTargetSRS.exportToWkt( &wkt ); + if ( err != CE_None || GDALSetProjection( hDstDS.get(), wkt ) != CE_None ) + { + CPLFree( wkt ); + return false; + } + CPLFree( wkt ); + } + + for ( int i = 0; i < GDALGetRasterCount( hSrcDS ); ++i ) + { + GDALRasterBandH hSrcBand = GDALGetRasterBand( hSrcDS, i + 1 ); + GDALRasterBandH hDstBand = GDALGetRasterBand( hDstDS.get(), i + 1 ); + GDALColorTableH cTable = GDALGetRasterColorTable( hSrcBand ); + GDALSetRasterColorInterpretation( hDstBand, GDALGetRasterColorInterpretation( hSrcBand ) ); + if ( cTable ) + { + GDALSetRasterColorTable( hDstBand, cTable ); + } + + int success; + const double noData = GDALGetRasterNoDataValue( hSrcBand, &success ); + if ( success ) + { + GDALSetRasterNoDataValue( hDstBand, noData ); + } + else if ( useZeroAsTrans ) + { + GDALSetRasterNoDataValue( hDstBand, 0 ); + } + } + + return true; +} + QgsImageWarper::Result QgsImageWarper::warpFile( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, ResamplingMethod resampling, bool useZeroAsTrans, const QString &compression, const QgsCoordinateReferenceSystem &crs, QgsFeedback *feedback, double destResX, double destResY ) { if ( !georefTransform.parametersInitialized() ) @@ -208,6 +274,91 @@ QgsImageWarper::Result QgsImageWarper::warpFile( const QString &input, const QSt : QgsImageWarper::Result::WarpFailure; } +QgsImageWarper::Result QgsImageWarper::warpFile( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, ResamplingMethod resampling, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs, QgsFeedback *feedback, double destResX, double destResY ) +{ + if ( !georefTransform.parametersInitialized() ) + return QgsImageWarper::Result::InvalidParameters; + + gdal::dataset_unique_ptr hSrcDS; + gdal::dataset_unique_ptr hDstDS; + gdal::warp_options_unique_ptr psWarpOptions; + if ( !openSrcDSAndGetWarpOpt( input, resampling, georefTransform.GDALTransformer(), hSrcDS, psWarpOptions ) ) + { + return QgsImageWarper::Result::SourceError; + } + + double adfGeoTransform[6]; + int destPixels, destLines; + CPLErr eErr = GDALSuggestedWarpOutput( hSrcDS.get(), georefTransform.GDALTransformer(), georefTransform.GDALTransformerArgs(), adfGeoTransform, &destPixels, &destLines ); + if ( eErr != CE_None ) + { + return QgsImageWarper::Result::TransformError; + } + + // If specified, override the suggested resolution with user values + if ( destResX != 0.0 || destResY != 0.0 ) + { + // If only one scale has been specified, fill in the other from the GDAL suggestion + if ( destResX == 0.0 ) + destResX = adfGeoTransform[1]; + if ( destResY == 0.0 ) + destResY = adfGeoTransform[5]; + + // Make sure user-specified coordinate system has canonical orientation + if ( destResX < 0.0 ) + destResX = -destResX; + if ( destResY > 0.0 ) + destResY = -destResY; + + // Assert that the north-up convention is fulfilled by GDALSuggestedWarpOutput (should always be the case) + // Asserts are bad as they just crash out, changed to just return false. TS + if ( adfGeoTransform[0] <= 0.0 || adfGeoTransform[5] >= 0.0 ) + { + QgsDebugError( QStringLiteral( "Image is not north up after GDALSuggestedWarpOutput, bailing out." ) ); + return QgsImageWarper::Result::InvalidParameters; + } + // Find suggested output image extent (in georeferenced units) + const double minX = adfGeoTransform[0]; + const double maxX = adfGeoTransform[0] + adfGeoTransform[1] * destPixels; + const double maxY = adfGeoTransform[3]; + const double minY = adfGeoTransform[3] + adfGeoTransform[5] * destLines; + + // Update line and pixel count to match extent at user-specified resolution + destPixels = ( int ) ( ( ( maxX - minX ) / destResX ) + 0.5 ); + destLines = ( int ) ( ( ( minY - maxY ) / destResY ) + 0.5 ); + adfGeoTransform[0] = minX; + adfGeoTransform[3] = maxY; + adfGeoTransform[1] = destResX; + adfGeoTransform[5] = destResY; + } + + if ( !createDestinationDataset( output, hSrcDS.get(), hDstDS, destPixels, destLines, adfGeoTransform, useZeroAsTrans, options, crs ) ) + { + return QgsImageWarper::Result::DestinationCreationError; + } + + // Set GDAL callbacks for the progress dialog + psWarpOptions->pProgressArg = reinterpret_cast( feedback ); + psWarpOptions->pfnProgress = updateWarpProgress; + + psWarpOptions->hSrcDS = hSrcDS.get(); + psWarpOptions->hDstDS = hDstDS.get(); + + // Create a transformer which transforms from source to destination pixels (and vice versa) + psWarpOptions->pfnTransformer = GeoToPixelTransform; + psWarpOptions->pTransformerArg = addGeoToPixelTransform( georefTransform.GDALTransformer(), georefTransform.GDALTransformerArgs(), adfGeoTransform ); + + // Initialize and execute the warp operation. + GDALWarpOperation oOperation; + oOperation.Initialize( psWarpOptions.get() ); + + eErr = oOperation.ChunkAndWarpImage( 0, 0, destPixels, destLines ); + + destroyGeoToPixelTransform( psWarpOptions->pTransformerArg ); + return feedback->isCanceled() ? QgsImageWarper::Result::Canceled : eErr == CE_None ? QgsImageWarper::Result::Success + : QgsImageWarper::Result::WarpFailure; +} + void *QgsImageWarper::addGeoToPixelTransform( GDALTransformerFunc GDALTransformer, void *GDALTransformerArg, double *padfGeotransform ) const { TransformChain *chain = new TransformChain; @@ -311,14 +462,14 @@ GDALResampleAlg QgsImageWarper::toGDALResampleAlg( const QgsImageWarper::Resampl // QgsImageWarperTask // -QgsImageWarperTask::QgsImageWarperTask( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, QgsImageWarper::ResamplingMethod resampling, bool useZeroAsTrans, const QString &compression, const QgsCoordinateReferenceSystem &crs, double destResX, double destResY ) +QgsImageWarperTask::QgsImageWarperTask( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, QgsImageWarper::ResamplingMethod resampling, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs, double destResX, double destResY ) : QgsTask( tr( "Warping %1" ).arg( input ), QgsTask::CanCancel ) , mInput( input ) , mOutput( output ) , mTransform( qgis::down_cast( georefTransform.clone() ) ) , mResamplingMethod( resampling ) , mUseZeroAsTrans( useZeroAsTrans ) - , mCompression( compression ) + , mCreationOptions( options ) , mDestinationCrs( crs ) , mDestinationResX( destResX ) , mDestinationResY( destResY ) @@ -345,7 +496,7 @@ bool QgsImageWarperTask::run() *mTransform.get(), mResamplingMethod, mUseZeroAsTrans, - mCompression, + mCreationOptions, mDestinationCrs, mFeedback.get(), mDestinationResX, diff --git a/src/app/georeferencer/qgsimagewarper.h b/src/app/georeferencer/qgsimagewarper.h index 398a7cbbd5202..12627ee47163f 100644 --- a/src/app/georeferencer/qgsimagewarper.h +++ b/src/app/georeferencer/qgsimagewarper.h @@ -76,6 +76,23 @@ class APP_EXPORT QgsImageWarper */ Result warpFile( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, ResamplingMethod resampling, bool useZeroAsTrans, const QString &compression, const QgsCoordinateReferenceSystem &crs, QgsFeedback *feedback, double destResX = 0.0, double destResY = 0.0 ); + /** + * Warp the file specified by \a input and write the resulting raster to the file \a output. + * \param input input file name + * \param output output file name + * \param georefTransform specifies the warp transformation which should be applied to \a input. + * \param resampling specifies image resampling algorithm to use. + * \param useZeroAsTrans specifies whether to mark transparent areas with a value of "zero". + * \param options raster creation options + * \param crs output file CRS + * \param feedback optional feedback object + * \param destResX The desired horizontal resolution of the output file, in target georeferenced units. A value of zero means automatic selection. + * \param destResY The desired vertical resolution of the output file, in target georeferenced units. A value of zero means automatic selection. + * + * \since QGIS 3.42 + */ + Result warpFile( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, ResamplingMethod resampling, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs, QgsFeedback *feedback, double destResX = 0.0, double destResY = 0.0 ); + private: struct TransformChain { @@ -102,6 +119,7 @@ class APP_EXPORT QgsImageWarper bool openSrcDSAndGetWarpOpt( const QString &input, ResamplingMethod resampling, const GDALTransformerFunc &pfnTransform, gdal::dataset_unique_ptr &hSrcDS, gdal::warp_options_unique_ptr &psWarpOptions ) const; bool createDestinationDataset( const QString &outputName, GDALDatasetH hSrcDS, gdal::dataset_unique_ptr &hDstDS, uint resX, uint resY, double *adfGeoTransform, bool useZeroAsTrans, const QString &compression, const QgsCoordinateReferenceSystem &crs ); + bool createDestinationDataset( const QString &outputName, GDALDatasetH hSrcDS, gdal::dataset_unique_ptr &hDstDS, uint resX, uint resY, double *adfGeoTransform, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs ); //! \brief GDAL progress callback, used to display warping progress via a QProgressDialog static int CPL_STDCALL updateWarpProgress( double dfComplete, const char *pszMessage, void *pProgressArg ); @@ -123,12 +141,12 @@ class QgsImageWarperTask : public QgsTask * \param georefTransform specifies the warp transformation which should be applied to \a input. * \param resampling specifies image resampling algorithm to use. * \param useZeroAsTrans specifies whether to mark transparent areas with a value of "zero". - * \param compression image compression method + * \param options raster creation options * \param crs output file CRS * \param destResX The desired horizontal resolution of the output file, in target georeferenced units. A value of zero means automatic selection. * \param destResY The desired vertical resolution of the output file, in target georeferenced units. A value of zero means automatic selection. */ - QgsImageWarperTask( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, QgsImageWarper::ResamplingMethod resampling, bool useZeroAsTrans, const QString &compression, const QgsCoordinateReferenceSystem &crs, double destResX = 0.0, double destResY = 0.0 ); + QgsImageWarperTask( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, QgsImageWarper::ResamplingMethod resampling, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs, double destResX = 0.0, double destResY = 0.0 ); void cancel() override; @@ -146,7 +164,7 @@ class QgsImageWarperTask : public QgsTask std::unique_ptr mTransform; QgsImageWarper::ResamplingMethod mResamplingMethod = QgsImageWarper::ResamplingMethod::Bilinear; bool mUseZeroAsTrans = false; - QString mCompression; + QStringList mCreationOptions; QgsCoordinateReferenceSystem mDestinationCrs; double mDestinationResX = 0; double mDestinationResY = 0; diff --git a/src/app/georeferencer/qgstransformsettingsdialog.cpp b/src/app/georeferencer/qgstransformsettingsdialog.cpp index 56fad3d9f1148..3b1620f5ab3b6 100644 --- a/src/app/georeferencer/qgstransformsettingsdialog.cpp +++ b/src/app/georeferencer/qgstransformsettingsdialog.cpp @@ -108,11 +108,7 @@ QgsTransformSettingsDialog::QgsTransformSettingsDialog( Qgis::LayerType type, co cmbTransformType->addItem( tr( "Thin Plate Spline" ), static_cast( QgsGcpTransformerInterface::TransformMethod::ThinPlateSpline ) ); cmbTransformType->addItem( tr( "Projective" ), static_cast( QgsGcpTransformerInterface::TransformMethod::Projective ) ); - // Populate CompressionComboBox - cmbCompressionComboBox->addItem( tr( "None" ), QStringLiteral( "None" ) ); - cmbCompressionComboBox->addItem( tr( "LZW" ), QStringLiteral( "LZW" ) ); - cmbCompressionComboBox->addItem( tr( "PACKBITS" ), QStringLiteral( "PACKBITS" ) ); - cmbCompressionComboBox->addItem( tr( "DEFLATE" ), QStringLiteral( "DEFLATE" ) ); + mCreationOptionsWidget->setFormat( "GTiff" ); cmbResampling->addItem( tr( "Nearest Neighbour" ), static_cast( QgsImageWarper::ResamplingMethod::NearestNeighbour ) ); cmbResampling->addItem( tr( "Bilinear (2x2 Kernel)" ), static_cast( QgsImageWarper::ResamplingMethod::Bilinear ) ); @@ -170,14 +166,14 @@ void QgsTransformSettingsDialog::setResamplingMethod( QgsImageWarper::Resampling cmbResampling->setCurrentIndex( cmbResampling->findData( static_cast( method ) ) ); } -QString QgsTransformSettingsDialog::compressionMethod() const +QStringList QgsTransformSettingsDialog::creationOptions() const { - return cmbCompressionComboBox->currentData().toString(); + return mCreationOptionsGroupBox->isChecked() ? mCreationOptionsWidget->options() : QStringList(); } -void QgsTransformSettingsDialog::setCompressionMethod( const QString &method ) +void QgsTransformSettingsDialog::setCreationOptions( const QString &options ) { - cmbCompressionComboBox->setCurrentIndex( cmbCompressionComboBox->findData( method ) ); + mCreationOptionsWidget->setOptions( options ); } QString QgsTransformSettingsDialog::destinationFilename() const @@ -280,6 +276,13 @@ void QgsTransformSettingsDialog::accept() outputFile->setFilePath( outputFileInfo.absoluteFilePath() ); } + const QString message = mCreationOptionsWidget->validateOptions( false ); + if ( !message.isNull() ) + { + QMessageBox::warning( this, tr( "Creation Options" ), tr( "Invalid creation options:\n%1" ).arg( message ) ); + return; + } + QDialog::accept(); } diff --git a/src/app/georeferencer/qgstransformsettingsdialog.h b/src/app/georeferencer/qgstransformsettingsdialog.h index bfa183e5c924e..08c80b817f348 100644 --- a/src/app/georeferencer/qgstransformsettingsdialog.h +++ b/src/app/georeferencer/qgstransformsettingsdialog.h @@ -73,14 +73,14 @@ class QgsTransformSettingsDialog : public QDialog, private Ui::QgsTransformSetti void setResamplingMethod( QgsImageWarper::ResamplingMethod method ); /** - * Returns the selected compression method. + * Returns raster creation options. */ - QString compressionMethod() const; + QStringList creationOptions() const; /** - * Sets the selected compression \a method. + * Sets raster creation options. */ - void setCompressionMethod( const QString &method ); + void setCreationOptions( const QString &options ); /** * Returns the destination filename. diff --git a/src/ui/georeferencer/qgstransformsettingsdialogbase.ui b/src/ui/georeferencer/qgstransformsettingsdialogbase.ui index 73021c397dc52..941522fc74b2c 100644 --- a/src/ui/georeferencer/qgstransformsettingsdialogbase.ui +++ b/src/ui/georeferencer/qgstransformsettingsdialogbase.ui @@ -7,7 +7,7 @@ 0 0 438 - 702 + 646 @@ -17,10 +17,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Help|QDialogButtonBox::StandardButton::Ok @@ -49,8 +49,8 @@ 0 - - + + 0 @@ -58,35 +58,19 @@ - Compression - - - cmbCompressionComboBox + Output file - - + + - Use 0 for transparency when needed - - - false - - - - - - - - 0 - 0 - + Create world file only (linear transforms) - - + + 0 @@ -94,17 +78,10 @@ - Output file + Resampling method - - - - - - - - - Create world file only (linear transforms) + + cmbResampling @@ -175,20 +152,32 @@ - - - - - 0 - 0 - - + + - Resampling method + Use 0 for transparency when needed - - cmbResampling + + false + + + + + + + + + + Raster creation options + + + true + + + + + @@ -250,12 +239,6 @@ Reports - - - - - - @@ -270,6 +253,12 @@ + + + + + +
@@ -318,7 +307,7 @@ - Qt::StrongFocus + Qt::FocusPolicy::StrongFocus @@ -328,7 +317,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -365,12 +354,23 @@ QDoubleSpinBox
georeferencer/qgsvalidateddoublespinbox.h
+ + QgsRasterFormatSaveOptionsWidget + QWidget +
qgsrasterformatsaveoptionswidget.h
+ 1 +
+ + QgsCollapsibleGroupBox + QGroupBox +
qgscollapsiblegroupbox.h
+ 1 +
cmbTransformType mCrsSelector cmbResampling - cmbCompressionComboBox mWorldFileCheckBox cbxZeroAsTrans cbxUserResolution From 03226d91e4f60bc265682187a80803a35c417a19 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Thu, 30 Jan 2025 08:25:40 +0000 Subject: [PATCH 42/81] adapt existing methods instead of creating overrides --- src/app/georeferencer/qgsimagewarper.cpp | 147 ----------------------- src/app/georeferencer/qgsimagewarper.h | 18 --- 2 files changed, 165 deletions(-) diff --git a/src/app/georeferencer/qgsimagewarper.cpp b/src/app/georeferencer/qgsimagewarper.cpp index 491c444b6b1ae..31430778536c7 100644 --- a/src/app/georeferencer/qgsimagewarper.cpp +++ b/src/app/georeferencer/qgsimagewarper.cpp @@ -61,68 +61,6 @@ bool QgsImageWarper::openSrcDSAndGetWarpOpt( const QString &input, ResamplingMet return true; } -bool QgsImageWarper::createDestinationDataset( const QString &outputName, GDALDatasetH hSrcDS, gdal::dataset_unique_ptr &hDstDS, uint resX, uint resY, double *adfGeoTransform, bool useZeroAsTrans, const QString &compression, const QgsCoordinateReferenceSystem &crs ) -{ - // create the output file - GDALDriverH driver = GDALGetDriverByName( "GTiff" ); - if ( !driver ) - { - return false; - } - char **papszOptions = nullptr; - papszOptions = CSLSetNameValue( papszOptions, "COMPRESS", compression.toLatin1() ); - hDstDS.reset( GDALCreate( driver, outputName.toUtf8().constData(), resX, resY, GDALGetRasterCount( hSrcDS ), GDALGetRasterDataType( GDALGetRasterBand( hSrcDS, 1 ) ), papszOptions ) ); - if ( !hDstDS ) - { - return false; - } - - if ( CE_None != GDALSetGeoTransform( hDstDS.get(), adfGeoTransform ) ) - { - return false; - } - - if ( crs.isValid() ) - { - OGRSpatialReference oTargetSRS; - oTargetSRS.importFromWkt( crs.toWkt( Qgis::CrsWktVariant::PreferredGdal ).toUtf8().data() ); - - char *wkt = nullptr; - const OGRErr err = oTargetSRS.exportToWkt( &wkt ); - if ( err != CE_None || GDALSetProjection( hDstDS.get(), wkt ) != CE_None ) - { - CPLFree( wkt ); - return false; - } - CPLFree( wkt ); - } - - for ( int i = 0; i < GDALGetRasterCount( hSrcDS ); ++i ) - { - GDALRasterBandH hSrcBand = GDALGetRasterBand( hSrcDS, i + 1 ); - GDALRasterBandH hDstBand = GDALGetRasterBand( hDstDS.get(), i + 1 ); - GDALColorTableH cTable = GDALGetRasterColorTable( hSrcBand ); - GDALSetRasterColorInterpretation( hDstBand, GDALGetRasterColorInterpretation( hSrcBand ) ); - if ( cTable ) - { - GDALSetRasterColorTable( hDstBand, cTable ); - } - - int success; - const double noData = GDALGetRasterNoDataValue( hSrcBand, &success ); - if ( success ) - { - GDALSetRasterNoDataValue( hDstBand, noData ); - } - else if ( useZeroAsTrans ) - { - GDALSetRasterNoDataValue( hDstBand, 0 ); - } - } - - return true; -} - bool QgsImageWarper::createDestinationDataset( const QString &outputName, GDALDatasetH hSrcDS, gdal::dataset_unique_ptr &hDstDS, uint resX, uint resY, double *adfGeoTransform, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs ) { // create the output file @@ -189,91 +127,6 @@ bool QgsImageWarper::createDestinationDataset( const QString &outputName, GDALDa return true; } -QgsImageWarper::Result QgsImageWarper::warpFile( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, ResamplingMethod resampling, bool useZeroAsTrans, const QString &compression, const QgsCoordinateReferenceSystem &crs, QgsFeedback *feedback, double destResX, double destResY ) -{ - if ( !georefTransform.parametersInitialized() ) - return QgsImageWarper::Result::InvalidParameters; - - gdal::dataset_unique_ptr hSrcDS; - gdal::dataset_unique_ptr hDstDS; - gdal::warp_options_unique_ptr psWarpOptions; - if ( !openSrcDSAndGetWarpOpt( input, resampling, georefTransform.GDALTransformer(), hSrcDS, psWarpOptions ) ) - { - return QgsImageWarper::Result::SourceError; - } - - double adfGeoTransform[6]; - int destPixels, destLines; - CPLErr eErr = GDALSuggestedWarpOutput( hSrcDS.get(), georefTransform.GDALTransformer(), georefTransform.GDALTransformerArgs(), adfGeoTransform, &destPixels, &destLines ); - if ( eErr != CE_None ) - { - return QgsImageWarper::Result::TransformError; - } - - // If specified, override the suggested resolution with user values - if ( destResX != 0.0 || destResY != 0.0 ) - { - // If only one scale has been specified, fill in the other from the GDAL suggestion - if ( destResX == 0.0 ) - destResX = adfGeoTransform[1]; - if ( destResY == 0.0 ) - destResY = adfGeoTransform[5]; - - // Make sure user-specified coordinate system has canonical orientation - if ( destResX < 0.0 ) - destResX = -destResX; - if ( destResY > 0.0 ) - destResY = -destResY; - - // Assert that the north-up convention is fulfilled by GDALSuggestedWarpOutput (should always be the case) - // Asserts are bad as they just crash out, changed to just return false. TS - if ( adfGeoTransform[0] <= 0.0 || adfGeoTransform[5] >= 0.0 ) - { - QgsDebugError( QStringLiteral( "Image is not north up after GDALSuggestedWarpOutput, bailing out." ) ); - return QgsImageWarper::Result::InvalidParameters; - } - // Find suggested output image extent (in georeferenced units) - const double minX = adfGeoTransform[0]; - const double maxX = adfGeoTransform[0] + adfGeoTransform[1] * destPixels; - const double maxY = adfGeoTransform[3]; - const double minY = adfGeoTransform[3] + adfGeoTransform[5] * destLines; - - // Update line and pixel count to match extent at user-specified resolution - destPixels = ( int ) ( ( ( maxX - minX ) / destResX ) + 0.5 ); - destLines = ( int ) ( ( ( minY - maxY ) / destResY ) + 0.5 ); - adfGeoTransform[0] = minX; - adfGeoTransform[3] = maxY; - adfGeoTransform[1] = destResX; - adfGeoTransform[5] = destResY; - } - - if ( !createDestinationDataset( output, hSrcDS.get(), hDstDS, destPixels, destLines, adfGeoTransform, useZeroAsTrans, compression, crs ) ) - { - return QgsImageWarper::Result::DestinationCreationError; - } - - // Set GDAL callbacks for the progress dialog - psWarpOptions->pProgressArg = reinterpret_cast( feedback ); - psWarpOptions->pfnProgress = updateWarpProgress; - - psWarpOptions->hSrcDS = hSrcDS.get(); - psWarpOptions->hDstDS = hDstDS.get(); - - // Create a transformer which transforms from source to destination pixels (and vice versa) - psWarpOptions->pfnTransformer = GeoToPixelTransform; - psWarpOptions->pTransformerArg = addGeoToPixelTransform( georefTransform.GDALTransformer(), georefTransform.GDALTransformerArgs(), adfGeoTransform ); - - // Initialize and execute the warp operation. - GDALWarpOperation oOperation; - oOperation.Initialize( psWarpOptions.get() ); - - eErr = oOperation.ChunkAndWarpImage( 0, 0, destPixels, destLines ); - - destroyGeoToPixelTransform( psWarpOptions->pTransformerArg ); - return feedback->isCanceled() ? QgsImageWarper::Result::Canceled : eErr == CE_None ? QgsImageWarper::Result::Success - : QgsImageWarper::Result::WarpFailure; -} - QgsImageWarper::Result QgsImageWarper::warpFile( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, ResamplingMethod resampling, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs, QgsFeedback *feedback, double destResX, double destResY ) { if ( !georefTransform.parametersInitialized() ) diff --git a/src/app/georeferencer/qgsimagewarper.h b/src/app/georeferencer/qgsimagewarper.h index 12627ee47163f..9ba60ec2a2343 100644 --- a/src/app/georeferencer/qgsimagewarper.h +++ b/src/app/georeferencer/qgsimagewarper.h @@ -61,21 +61,6 @@ class APP_EXPORT QgsImageWarper }; Q_ENUM( Result ) - /** - * Warp the file specified by \a input and write the resulting raster to the file \a output. - * \param input input file name - * \param output output file name - * \param georefTransform specifies the warp transformation which should be applied to \a input. - * \param resampling specifies image resampling algorithm to use. - * \param useZeroAsTrans specifies whether to mark transparent areas with a value of "zero". - * \param compression image compression method - * \param crs output file CRS - * \param feedback optional feedback object - * \param destResX The desired horizontal resolution of the output file, in target georeferenced units. A value of zero means automatic selection. - * \param destResY The desired vertical resolution of the output file, in target georeferenced units. A value of zero means automatic selection. - */ - Result warpFile( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, ResamplingMethod resampling, bool useZeroAsTrans, const QString &compression, const QgsCoordinateReferenceSystem &crs, QgsFeedback *feedback, double destResX = 0.0, double destResY = 0.0 ); - /** * Warp the file specified by \a input and write the resulting raster to the file \a output. * \param input input file name @@ -88,8 +73,6 @@ class APP_EXPORT QgsImageWarper * \param feedback optional feedback object * \param destResX The desired horizontal resolution of the output file, in target georeferenced units. A value of zero means automatic selection. * \param destResY The desired vertical resolution of the output file, in target georeferenced units. A value of zero means automatic selection. - * - * \since QGIS 3.42 */ Result warpFile( const QString &input, const QString &output, const QgsGeorefTransform &georefTransform, ResamplingMethod resampling, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs, QgsFeedback *feedback, double destResX = 0.0, double destResY = 0.0 ); @@ -118,7 +101,6 @@ class APP_EXPORT QgsImageWarper bool openSrcDSAndGetWarpOpt( const QString &input, ResamplingMethod resampling, const GDALTransformerFunc &pfnTransform, gdal::dataset_unique_ptr &hSrcDS, gdal::warp_options_unique_ptr &psWarpOptions ) const; - bool createDestinationDataset( const QString &outputName, GDALDatasetH hSrcDS, gdal::dataset_unique_ptr &hDstDS, uint resX, uint resY, double *adfGeoTransform, bool useZeroAsTrans, const QString &compression, const QgsCoordinateReferenceSystem &crs ); bool createDestinationDataset( const QString &outputName, GDALDatasetH hSrcDS, gdal::dataset_unique_ptr &hDstDS, uint resX, uint resY, double *adfGeoTransform, bool useZeroAsTrans, const QStringList &options, const QgsCoordinateReferenceSystem &crs ); //! \brief GDAL progress callback, used to display warping progress via a QProgressDialog From 6bf6d0425432047eae9667453d9d7a05df9ade76 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Thu, 30 Jan 2025 08:33:05 +0000 Subject: [PATCH 43/81] do not translate settings descriptions --- src/app/georeferencer/qgsgeorefmainwindow.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/app/georeferencer/qgsgeorefmainwindow.cpp b/src/app/georeferencer/qgsgeorefmainwindow.cpp index ef15e84cf7642..726d6d62df87f 100644 --- a/src/app/georeferencer/qgsgeorefmainwindow.cpp +++ b/src/app/georeferencer/qgsgeorefmainwindow.cpp @@ -76,27 +76,27 @@ #include "qgssettingsentryenumflag.h" #include "qgslayoutexporter.h" -const QgsSettingsEntryEnumFlag *QgsGeoreferencerMainWindow::settingResamplingMethod = new QgsSettingsEntryEnumFlag( QStringLiteral( "resampling-method" ), sTreeGeoreferencer, QgsImageWarper::ResamplingMethod::NearestNeighbour, QObject::tr( "Last used georeferencer resampling method" ) ); +const QgsSettingsEntryEnumFlag *QgsGeoreferencerMainWindow::settingResamplingMethod = new QgsSettingsEntryEnumFlag( QStringLiteral( "resampling-method" ), sTreeGeoreferencer, QgsImageWarper::ResamplingMethod::NearestNeighbour, QStringLiteral( "Last used georeferencer resampling method" ) ); -const QgsSettingsEntryStringList *QgsGeoreferencerMainWindow::settingCreationOptions = new QgsSettingsEntryStringList( QStringLiteral( "creation-options" ), sTreeGeoreferencer, QStringList(), QObject::tr( "Last used georeferencer raster creation options" ) ); +const QgsSettingsEntryStringList *QgsGeoreferencerMainWindow::settingCreationOptions = new QgsSettingsEntryStringList( QStringLiteral( "creation-options" ), sTreeGeoreferencer, QStringList(), QStringLiteral( "Last used georeferencer raster creation options" ) ); -const QgsSettingsEntryBool *QgsGeoreferencerMainWindow::settingUseZeroForTransparent = new QgsSettingsEntryBool( QStringLiteral( "use-zero-for-transparent" ), sTreeGeoreferencer, false, QObject::tr( "Last used georeferencer use-zero-as-transparent option" ) ); +const QgsSettingsEntryBool *QgsGeoreferencerMainWindow::settingUseZeroForTransparent = new QgsSettingsEntryBool( QStringLiteral( "use-zero-for-transparent" ), sTreeGeoreferencer, false, QStringLiteral( "Last used georeferencer use-zero-as-transparent option" ) ); -const QgsSettingsEntryEnumFlag *QgsGeoreferencerMainWindow::settingTransformMethod = new QgsSettingsEntryEnumFlag( QStringLiteral( "transform-method" ), sTreeGeoreferencer, QgsGcpTransformerInterface::TransformMethod::Linear, QObject::tr( "Last used georeferencer transform method" ) ); +const QgsSettingsEntryEnumFlag *QgsGeoreferencerMainWindow::settingTransformMethod = new QgsSettingsEntryEnumFlag( QStringLiteral( "transform-method" ), sTreeGeoreferencer, QgsGcpTransformerInterface::TransformMethod::Linear, QStringLiteral( "Last used georeferencer transform method" ) ); -const QgsSettingsEntryBool *QgsGeoreferencerMainWindow::settingSaveGcps = new QgsSettingsEntryBool( QStringLiteral( "save-gcp-points" ), sTreeGeoreferencer, false, QObject::tr( "Whether georeferencer should automatically save .points files" ) ); +const QgsSettingsEntryBool *QgsGeoreferencerMainWindow::settingSaveGcps = new QgsSettingsEntryBool( QStringLiteral( "save-gcp-points" ), sTreeGeoreferencer, false, QStringLiteral( "Whether georeferencer should automatically save .points files" ) ); -const QgsSettingsEntryBool *QgsGeoreferencerMainWindow::settingLoadInProject = new QgsSettingsEntryBool( QStringLiteral( "load-result-in-project" ), sTreeGeoreferencer, true, QObject::tr( "Whether georeferencer should automatically load results into the current project" ) ); +const QgsSettingsEntryBool *QgsGeoreferencerMainWindow::settingLoadInProject = new QgsSettingsEntryBool( QStringLiteral( "load-result-in-project" ), sTreeGeoreferencer, true, QStringLiteral( "Whether georeferencer should automatically load results into the current project" ) ); -const QgsSettingsEntryString *QgsGeoreferencerMainWindow::settingLastSourceFolder = new QgsSettingsEntryString( QStringLiteral( "last-source-folder" ), sTreeGeoreferencer, QString(), QObject::tr( "Last used folder for georeferencer source files" ) ); +const QgsSettingsEntryString *QgsGeoreferencerMainWindow::settingLastSourceFolder = new QgsSettingsEntryString( QStringLiteral( "last-source-folder" ), sTreeGeoreferencer, QString(), QStringLiteral( "Last used folder for georeferencer source files" ) ); -const QgsSettingsEntryString *QgsGeoreferencerMainWindow::settingLastRasterFileFilter = new QgsSettingsEntryString( QStringLiteral( "last-raster-file-filter" ), sTreeGeoreferencer, QString(), QObject::tr( "Last used raster file filter for georeferencer source files" ) ); +const QgsSettingsEntryString *QgsGeoreferencerMainWindow::settingLastRasterFileFilter = new QgsSettingsEntryString( QStringLiteral( "last-raster-file-filter" ), sTreeGeoreferencer, QString(), QStringLiteral( "Last used raster file filter for georeferencer source files" ) ); -const QgsSettingsEntryString *QgsGeoreferencerMainWindow::settingLastTargetCrs = new QgsSettingsEntryString( QStringLiteral( "last-target-crs" ), sTreeGeoreferencer, QString(), QObject::tr( "Last used georeferencer target CRS" ) ); +const QgsSettingsEntryString *QgsGeoreferencerMainWindow::settingLastTargetCrs = new QgsSettingsEntryString( QStringLiteral( "last-target-crs" ), sTreeGeoreferencer, QString(), QStringLiteral( "Last used georeferencer target CRS" ) ); -const QgsSettingsEntryBool *QgsGeoreferencerMainWindow::settingSnappingEnabled = new QgsSettingsEntryBool( QStringLiteral( "snapping-enabled" ), sTreeGeoreferencer, false, QObject::tr( "Snapping enabled." ) ); +const QgsSettingsEntryBool *QgsGeoreferencerMainWindow::settingSnappingEnabled = new QgsSettingsEntryBool( QStringLiteral( "snapping-enabled" ), sTreeGeoreferencer, false, QStringLiteral( "Snapping enabled." ) ); -const QgsSettingsEntryEnumFlag *QgsGeoreferencerMainWindow::settingSnappingTypes = new QgsSettingsEntryEnumFlag( QStringLiteral( "snapping-types" ), sTreeGeoreferencer, Qgis::SnappingType::Vertex, QObject::tr( "Snapping types." ) ); +const QgsSettingsEntryEnumFlag *QgsGeoreferencerMainWindow::settingSnappingTypes = new QgsSettingsEntryEnumFlag( QStringLiteral( "snapping-types" ), sTreeGeoreferencer, Qgis::SnappingType::Vertex, QStringLiteral( "Snapping types." ) ); QgsGeorefDockWidget::QgsGeorefDockWidget( const QString &title, QWidget *parent, Qt::WindowFlags flags ) From 03987344d66c06a1fbfa525d63c0b1982ae3a64a Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 30 Jan 2025 14:40:02 +1000 Subject: [PATCH 44/81] Use font button in annotation widgets instead of full text format widget The widgets were getting very complex, this reduces the amount of controls shown in the dock --- .../qgsannotationitemwidget_impl.cpp | 98 ++--- .../qgsannotationitemwidget_impl.h | 6 - .../qgsannotationlinetextwidgetbase.ui | 56 ++- .../qgsannotationpointtextwidgetbase.ui | 87 ++-- .../qgsannotationrectangulartextwidgetbase.ui | 382 +++++++++--------- src/ui/qgsrichtexteditorbase.ui | 4 +- 6 files changed, 338 insertions(+), 295 deletions(-) diff --git a/src/gui/annotations/qgsannotationitemwidget_impl.cpp b/src/gui/annotations/qgsannotationitemwidget_impl.cpp index e05dd7f90657d..82a90e55167d5 100644 --- a/src/gui/annotations/qgsannotationitemwidget_impl.cpp +++ b/src/gui/annotations/qgsannotationitemwidget_impl.cpp @@ -314,14 +314,9 @@ QgsAnnotationPointTextItemWidget::QgsAnnotationPointTextItemWidget( QWidget *par { setupUi( this ); - mTextFormatWidget = new QgsTextFormatWidget(); - QVBoxLayout *vLayout = new QVBoxLayout(); - vLayout->setContentsMargins( 0, 0, 0, 0 ); - vLayout->addWidget( mTextFormatWidget ); - mTextFormatWidgetContainer->setLayout( vLayout ); - mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer ); - mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 ); + + mTextFormatButton->setMode( QgsFontButton::ModeTextRenderer ); mSpinTextAngle->setClearValue( 0 ); @@ -330,10 +325,9 @@ QgsAnnotationPointTextItemWidget::QgsAnnotationPointTextItemWidget( QWidget *par mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight ); - mTextFormatWidget->setDockMode( dockMode() ); - connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [=] { + connect( mTextFormatButton, &QgsFontButton::changed, this, [=] { mTextEdit->setMode( - mTextFormatWidget->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText + mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText ); if ( !mBlockChangedSignal ) @@ -377,8 +371,8 @@ void QgsAnnotationPointTextItemWidget::updateItem( QgsAnnotationItem *item ) if ( QgsAnnotationPointTextItem *pointTextItem = dynamic_cast( item ) ) { mBlockChangedSignal = true; - pointTextItem->setFormat( mTextFormatWidget->format() ); - pointTextItem->setText( mTextFormatWidget->format().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() ); + pointTextItem->setFormat( mTextFormatButton->textFormat() ); + pointTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() ); pointTextItem->setAngle( mSpinTextAngle->value() ); pointTextItem->setRotationMode( mRotationModeCombo->currentData().value() ); pointTextItem->setAlignment( mAlignmentComboBox->currentAlignment() ); @@ -387,18 +381,14 @@ void QgsAnnotationPointTextItemWidget::updateItem( QgsAnnotationItem *item ) } } -void QgsAnnotationPointTextItemWidget::setDockMode( bool dockMode ) -{ - QgsAnnotationItemBaseWidget::setDockMode( dockMode ); - if ( mTextFormatWidget ) - mTextFormatWidget->setDockMode( dockMode ); -} - void QgsAnnotationPointTextItemWidget::setContext( const QgsSymbolWidgetContext &context ) { QgsAnnotationItemBaseWidget::setContext( context ); - if ( mTextFormatWidget ) - mTextFormatWidget->setContext( context ); + if ( mTextFormatButton ) + { + mTextFormatButton->setMapCanvas( context.mapCanvas() ); + mTextFormatButton->setMessageBar( context.messageBar() ); + } mPropertiesWidget->setContext( context ); } @@ -419,7 +409,7 @@ bool QgsAnnotationPointTextItemWidget::setNewItem( QgsAnnotationItem *item ) mItem.reset( textItem->clone() ); mBlockChangedSignal = true; - mTextFormatWidget->setFormat( mItem->format() ); + mTextFormatButton->setTextFormat( mItem->format() ); mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText ); mTextEdit->setText( mItem->text() ); mSpinTextAngle->setValue( mItem->angle() ); @@ -464,19 +454,13 @@ QgsAnnotationLineTextItemWidget::QgsAnnotationLineTextItemWidget( QWidget *paren { setupUi( this ); - mTextFormatWidget = new QgsTextFormatWidget(); - QVBoxLayout *vLayout = new QVBoxLayout(); - vLayout->setContentsMargins( 0, 0, 0, 0 ); - vLayout->addWidget( mTextFormatWidget ); - mTextFormatWidgetContainer->setLayout( vLayout ); + mTextFormatButton->setMode( QgsFontButton::ModeTextRenderer ); mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer ); - mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 ); - mTextFormatWidget->setDockMode( dockMode() ); - connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [=] { + connect( mTextFormatButton, &QgsFontButton::changed, this, [=] { mTextEdit->setMode( - mTextFormatWidget->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText + mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText ); if ( !mBlockChangedSignal ) @@ -519,8 +503,8 @@ void QgsAnnotationLineTextItemWidget::updateItem( QgsAnnotationItem *item ) if ( QgsAnnotationLineTextItem *lineTextItem = dynamic_cast( item ) ) { mBlockChangedSignal = true; - lineTextItem->setFormat( mTextFormatWidget->format() ); - lineTextItem->setText( mTextFormatWidget->format().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() ); + lineTextItem->setFormat( mTextFormatButton->textFormat() ); + lineTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() ); lineTextItem->setOffsetFromLine( mSpinOffset->value() ); lineTextItem->setOffsetFromLineUnit( mOffsetUnitWidget->unit() ); @@ -531,18 +515,14 @@ void QgsAnnotationLineTextItemWidget::updateItem( QgsAnnotationItem *item ) } } -void QgsAnnotationLineTextItemWidget::setDockMode( bool dockMode ) -{ - QgsAnnotationItemBaseWidget::setDockMode( dockMode ); - if ( mTextFormatWidget ) - mTextFormatWidget->setDockMode( dockMode ); -} - void QgsAnnotationLineTextItemWidget::setContext( const QgsSymbolWidgetContext &context ) { QgsAnnotationItemBaseWidget::setContext( context ); - if ( mTextFormatWidget ) - mTextFormatWidget->setContext( context ); + if ( mTextFormatButton ) + { + mTextFormatButton->setMapCanvas( context.mapCanvas() ); + mTextFormatButton->setMessageBar( context.messageBar() ); + } mPropertiesWidget->setContext( context ); } @@ -561,7 +541,7 @@ bool QgsAnnotationLineTextItemWidget::setNewItem( QgsAnnotationItem *item ) mItem.reset( textItem->clone() ); mBlockChangedSignal = true; - mTextFormatWidget->setFormat( mItem->format() ); + mTextFormatButton->setTextFormat( mItem->format() ); mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText ); mTextEdit->setText( mItem->text() ); mPropertiesWidget->setItem( mItem.get() ); @@ -628,22 +608,16 @@ QgsAnnotationRectangleTextItemWidget::QgsAnnotationRectangleTextItemWidget( QWid mSpinLeftMargin->setClearValue( 0 ); mMarginUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << Qgis::RenderUnit::Millimeters << Qgis::RenderUnit::MetersInMapUnits << Qgis::RenderUnit::MapUnits << Qgis::RenderUnit::Pixels << Qgis::RenderUnit::Points << Qgis::RenderUnit::Inches ); - mTextFormatWidget = new QgsTextFormatWidget(); - QVBoxLayout *vLayout = new QVBoxLayout(); - vLayout->setContentsMargins( 0, 0, 0, 0 ); - vLayout->addWidget( mTextFormatWidget ); - mTextFormatWidgetContainer->setLayout( vLayout ); + mTextFormatButton->setMode( QgsFontButton::ModeTextRenderer ); mTextEdit->setMode( QgsRichTextEditor::Mode::QgsTextRenderer ); - mTextEdit->setMaximumHeight( mTextEdit->fontMetrics().height() * 10 ); mAlignmentComboBox->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight | Qt::AlignJustify ); mVerticalAlignmentComboBox->setAvailableAlignments( Qt::AlignTop | Qt::AlignVCenter | Qt::AlignBottom ); - mTextFormatWidget->setDockMode( dockMode() ); - connect( mTextFormatWidget, &QgsTextFormatWidget::widgetChanged, this, [this] { + connect( mTextFormatButton, &QgsFontButton::changed, this, [this] { mTextEdit->setMode( - mTextFormatWidget->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText + mTextFormatButton->textFormat().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText ); onWidgetChanged(); @@ -685,8 +659,8 @@ void QgsAnnotationRectangleTextItemWidget::updateItem( QgsAnnotationItem *item ) if ( QgsAnnotationRectangleTextItem *rectTextItem = dynamic_cast( item ) ) { mBlockChangedSignal = true; - rectTextItem->setFormat( mTextFormatWidget->format() ); - rectTextItem->setText( mTextFormatWidget->format().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() ); + rectTextItem->setFormat( mTextFormatButton->textFormat() ); + rectTextItem->setText( mTextFormatButton->textFormat().allowHtmlFormatting() ? mTextEdit->toHtml() : mTextEdit->toPlainText() ); rectTextItem->setAlignment( mAlignmentComboBox->currentAlignment() | mVerticalAlignmentComboBox->currentAlignment() ); rectTextItem->setPlacementMode( mSizeModeCombo->currentData().value() ); @@ -714,18 +688,14 @@ void QgsAnnotationRectangleTextItemWidget::updateItem( QgsAnnotationItem *item ) } } -void QgsAnnotationRectangleTextItemWidget::setDockMode( bool dockMode ) -{ - QgsAnnotationItemBaseWidget::setDockMode( dockMode ); - if ( mTextFormatWidget ) - mTextFormatWidget->setDockMode( dockMode ); -} - void QgsAnnotationRectangleTextItemWidget::setContext( const QgsSymbolWidgetContext &context ) { QgsAnnotationItemBaseWidget::setContext( context ); - if ( mTextFormatWidget ) - mTextFormatWidget->setContext( context ); + if ( mTextFormatButton ) + { + mTextFormatButton->setMapCanvas( context.mapCanvas() ); + mTextFormatButton->setMessageBar( context.messageBar() ); + } mBackgroundSymbolButton->setMapCanvas( context.mapCanvas() ); mBackgroundSymbolButton->setMessageBar( context.messageBar() ); mFrameSymbolButton->setMapCanvas( context.mapCanvas() ); @@ -760,7 +730,7 @@ bool QgsAnnotationRectangleTextItemWidget::setNewItem( QgsAnnotationItem *item ) mItem.reset( textItem->clone() ); mBlockChangedSignal = true; - mTextFormatWidget->setFormat( mItem->format() ); + mTextFormatButton->setTextFormat( mItem->format() ); mTextEdit->setMode( mItem->format().allowHtmlFormatting() ? QgsRichTextEditor::Mode::QgsTextRenderer : QgsRichTextEditor::Mode::PlainText ); mTextEdit->setText( mItem->text() ); mAlignmentComboBox->setCurrentAlignment( mItem->alignment() & Qt::AlignHorizontal_Mask ); diff --git a/src/gui/annotations/qgsannotationitemwidget_impl.h b/src/gui/annotations/qgsannotationitemwidget_impl.h index 4fa3a6bdfe6b8..175602f731059 100644 --- a/src/gui/annotations/qgsannotationitemwidget_impl.h +++ b/src/gui/annotations/qgsannotationitemwidget_impl.h @@ -121,7 +121,6 @@ class QgsAnnotationPointTextItemWidget : public QgsAnnotationItemBaseWidget, pri ~QgsAnnotationPointTextItemWidget() override; QgsAnnotationItem *createItem() override; void updateItem( QgsAnnotationItem *item ) override; - void setDockMode( bool dockMode ) override; void setContext( const QgsSymbolWidgetContext &context ) override; public slots: @@ -134,7 +133,6 @@ class QgsAnnotationPointTextItemWidget : public QgsAnnotationItemBaseWidget, pri private: void mInsertExpressionButton_clicked(); - QgsTextFormatWidget *mTextFormatWidget = nullptr; bool mBlockChangedSignal = false; std::unique_ptr mItem; }; @@ -149,7 +147,6 @@ class QgsAnnotationRectangleTextItemWidget : public QgsAnnotationItemBaseWidget, ~QgsAnnotationRectangleTextItemWidget() override; QgsAnnotationItem *createItem() override; void updateItem( QgsAnnotationItem *item ) override; - void setDockMode( bool dockMode ) override; void setContext( const QgsSymbolWidgetContext &context ) override; QgsExpressionContext createExpressionContext() const override; @@ -170,7 +167,6 @@ class QgsAnnotationRectangleTextItemWidget : public QgsAnnotationItemBaseWidget, private: void mInsertExpressionButton_clicked(); - QgsTextFormatWidget *mTextFormatWidget = nullptr; bool mBlockChangedSignal = false; bool mUpdateItemPosition = false; @@ -186,7 +182,6 @@ class QgsAnnotationLineTextItemWidget : public QgsAnnotationItemBaseWidget, priv ~QgsAnnotationLineTextItemWidget() override; QgsAnnotationItem *createItem() override; void updateItem( QgsAnnotationItem *item ) override; - void setDockMode( bool dockMode ) override; void setContext( const QgsSymbolWidgetContext &context ) override; public slots: @@ -199,7 +194,6 @@ class QgsAnnotationLineTextItemWidget : public QgsAnnotationItemBaseWidget, priv private: void mInsertExpressionButton_clicked(); - QgsTextFormatWidget *mTextFormatWidget = nullptr; bool mBlockChangedSignal = false; std::unique_ptr mItem; }; diff --git a/src/ui/annotations/qgsannotationlinetextwidgetbase.ui b/src/ui/annotations/qgsannotationlinetextwidgetbase.ui index 49bc5e5b39149..7b085b40774dc 100644 --- a/src/ui/annotations/qgsannotationlinetextwidgetbase.ui +++ b/src/ui/annotations/qgsannotationlinetextwidgetbase.ui @@ -13,7 +13,7 @@ Point Text Annotation - + 0 @@ -26,7 +26,27 @@ 0 - + + + + Text format + + + + + + + + 0 + 0 + + + + Text format + + + + @@ -38,17 +58,17 @@ Insert/Edit Expression… - QToolButton::ToolButtonPopupMode::MenuButtonPopup + QToolButton::MenuButtonPopup - Qt::ToolButtonStyle::ToolButtonTextOnly + Qt::ToolButtonTextOnly - Qt::ArrowType::DownArrow + Qt::DownArrow - + @@ -58,7 +78,7 @@ - + Properties @@ -100,7 +120,7 @@
- Qt::FocusPolicy::StrongFocus + Qt::StrongFocus
@@ -116,26 +136,28 @@ - + - - - + + QgsDoubleSpinBox + QDoubleSpinBox +
qgsdoublespinbox.h
+
+ + QgsFontButton + QToolButton +
qgsfontbutton.h
+
QgsAnnotationItemCommonPropertiesWidget QWidget
qgsannotationitemcommonpropertieswidget.h
1
- - QgsDoubleSpinBox - QDoubleSpinBox -
qgsdoublespinbox.h
-
QgsRichTextEditor QWidget diff --git a/src/ui/annotations/qgsannotationpointtextwidgetbase.ui b/src/ui/annotations/qgsannotationpointtextwidgetbase.ui index 2bd54142f3649..b3285951679ab 100644 --- a/src/ui/annotations/qgsannotationpointtextwidgetbase.ui +++ b/src/ui/annotations/qgsannotationpointtextwidgetbase.ui @@ -13,7 +13,7 @@ Point Text Annotation - + 0 @@ -26,11 +26,14 @@ 0 - - - + + + 0 + 0 + + Rotation @@ -70,16 +73,13 @@
- - - - - - - - 0 - 150 - + + + + + 0 + 0 + @@ -95,45 +95,80 @@ Insert/Edit Expression… - QToolButton::ToolButtonPopupMode::MenuButtonPopup + QToolButton::MenuButtonPopup - Qt::ToolButtonStyle::ToolButtonTextOnly + Qt::ToolButtonTextOnly - Qt::ArrowType::DownArrow + Qt::DownArrow - + + + + Alignment + + + + + + + + + 0 + 0 + + + + Text format + + + + + + + + 0 + 2 + + + + - + - Alignment + Text format - - QgsAnnotationItemCommonPropertiesWidget - QWidget -
qgsannotationitemcommonpropertieswidget.h
- 1 -
QgsDoubleSpinBox QDoubleSpinBox
qgsdoublespinbox.h
+ + QgsFontButton + QToolButton +
qgsfontbutton.h
+
QgsAlignmentComboBox QComboBox
qgsalignmentcombobox.h
+ + QgsAnnotationItemCommonPropertiesWidget + QWidget +
qgsannotationitemcommonpropertieswidget.h
+ 1 +
QgsRichTextEditor QWidget diff --git a/src/ui/annotations/qgsannotationrectangulartextwidgetbase.ui b/src/ui/annotations/qgsannotationrectangulartextwidgetbase.ui index aafa452027e22..338856556832f 100644 --- a/src/ui/annotations/qgsannotationrectangulartextwidgetbase.ui +++ b/src/ui/annotations/qgsannotationrectangulartextwidgetbase.ui @@ -7,7 +7,7 @@ 0 0 321 - 716 + 779 @@ -23,13 +23,67 @@ 0 - - - - - 0 - 150 - + + + + Frame + + + true + + + + + + Symbol + + + + + + + + 0 + 0 + + + + Change… + + + + + + + + + + + + + Vertical alignment + + + + + + + + 0 + 0 + + + + Insert/Edit Expression… + + + QToolButton::MenuButtonPopup + + + Qt::ToolButtonTextOnly + + + Qt::DownArrow @@ -65,19 +119,119 @@ - - + + + + + + + + + + Horizontal alignment + + + + + + + + + + Width + + + + + + + + 0 + 0 + + + + 6 + + + 100000.000000000000000 + + + 0.200000000000000 + + + 1.000000000000000 + + + false + + + + + + + Height + + + + + + + + 0 + 0 + + + + 6 + + + 100000.000000000000000 + + + 0.200000000000000 + + + 1.000000000000000 + + + false + + + + + + + Unit + + + + + + + + 0 + 0 + + + + Qt::StrongFocus + + + + + + + + 0 - 0 + 150 - - - @@ -247,209 +401,77 @@ - - - - Vertical alignment - - - - + - Horizontal alignment + Text format - - - - - - - - - - Frame - - - true - - - - - - Symbol - - - - - - - - 0 - 0 - - - - Change… - - - - - - - - - - - - - Width - - - - - - - - 0 - 0 - - - - 6 - - - 100000.000000000000000 - - - 0.200000000000000 - - - 1.000000000000000 - - - false - - - - - - - Height - - - - - - - - 0 - 0 - - - - 6 - - - 100000.000000000000000 - - - 0.200000000000000 - - - 1.000000000000000 - - - false - - - - - - - Unit - - - - - - - - 0 - 0 - - - - Qt::StrongFocus - - - - - - - - - - + - + 0 0 - Insert/Edit Expression… - - - QToolButton::MenuButtonPopup - - - Qt::ToolButtonTextOnly + Text format - - Qt::DownArrow + + + + + + + 0 + 0 + - - QgsAnnotationItemCommonPropertiesWidget - QWidget -
qgsannotationitemcommonpropertieswidget.h
- 1 -
- - QgsSymbolButton - QToolButton -
qgssymbolbutton.h
-
QgsDoubleSpinBox QDoubleSpinBox
qgsdoublespinbox.h
- QgsUnitSelectionWidget - QWidget -
qgsunitselectionwidget.h
- 1 + QgsFontButton + QToolButton +
qgsfontbutton.h
QgsAlignmentComboBox QComboBox
qgsalignmentcombobox.h
+ + QgsAnnotationItemCommonPropertiesWidget + QWidget +
qgsannotationitemcommonpropertieswidget.h
+ 1 +
QgsRichTextEditor QWidget
qgsrichtexteditor.h
1
+ + QgsSymbolButton + QToolButton +
qgssymbolbutton.h
+
+ + QgsUnitSelectionWidget + QWidget +
qgsunitselectionwidget.h
+ 1 +
QgsCollapsibleGroupBox QGroupBox diff --git a/src/ui/qgsrichtexteditorbase.ui b/src/ui/qgsrichtexteditorbase.ui index 06573732ad7c9..b0e9f7dc58a1a 100644 --- a/src/ui/qgsrichtexteditorbase.ui +++ b/src/ui/qgsrichtexteditorbase.ui @@ -7,7 +7,7 @@ 0 0 846 - 312 + 705
@@ -51,7 +51,7 @@ - QTextEdit::AutoFormattingFlag::AutoNone + QTextEdit::AutoNone true From b3a88a247a1c6e8fea34cdc3d15c8f94834f5017 Mon Sep 17 00:00:00 2001 From: Patrik Sylve Date: Thu, 30 Jan 2025 16:45:05 +0100 Subject: [PATCH 45/81] Register vector tile label features first when all tiles are fetched --- src/core/vectortile/qgsvectortilelayerrenderer.cpp | 12 +++++++++++- src/core/vectortile/qgsvectortilelayerrenderer.h | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/core/vectortile/qgsvectortilelayerrenderer.cpp b/src/core/vectortile/qgsvectortilelayerrenderer.cpp index 3e854dd931e5a..797e960615b42 100644 --- a/src/core/vectortile/qgsvectortilelayerrenderer.cpp +++ b/src/core/vectortile/qgsvectortilelayerrenderer.cpp @@ -224,6 +224,15 @@ bool QgsVectorTileLayerRenderer::render() mErrors.append( asyncLoader->error() ); } + // Register labels features when all tiles are fetched to ensure consistent labeling + if ( mLabelProvider ) + { + for ( const auto &tile : mTileDataMap ) + { + mLabelProvider->registerTileFeatures( tile, ctx ); + } + } + if ( ctx.flags() & Qgis::RenderContextFlag::DrawSelection ) mRenderer->renderSelectedFeatures( mSelectedFeatures, ctx ); @@ -309,8 +318,9 @@ void QgsVectorTileLayerRenderer::decodeAndDrawTile( const QgsVectorTileRawData & mTotalDrawTime += tDraw.elapsed(); } + // Store tile for later use if ( mLabelProvider ) - mLabelProvider->registerTileFeatures( tile, ctx ); + mTileDataMap.insert( tile.id().toString(), tile ); if ( mDrawTileBoundaries ) { diff --git a/src/core/vectortile/qgsvectortilelayerrenderer.h b/src/core/vectortile/qgsvectortilelayerrenderer.h index 127f55d860a76..e024d636b418f 100644 --- a/src/core/vectortile/qgsvectortilelayerrenderer.h +++ b/src/core/vectortile/qgsvectortilelayerrenderer.h @@ -71,6 +71,9 @@ class QgsVectorTileLayerRenderer : public QgsMapLayerRenderer */ QgsVectorTileLabelProvider *mLabelProvider = nullptr; + // Decoded tile data + QMap mTileDataMap; + //! Whether to draw boundaries of tiles (useful for debugging) bool mDrawTileBoundaries = false; From 9e0e881bd07765bf0382c83017aa87926b505721 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Thu, 30 Jan 2025 11:26:12 +0000 Subject: [PATCH 46/81] update raster resampling widgets after loading a style (fix #56771) --- src/gui/raster/qgsrasterlayerproperties.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/raster/qgsrasterlayerproperties.cpp b/src/gui/raster/qgsrasterlayerproperties.cpp index a8db645d107b5..0c7496dcae783 100644 --- a/src/gui/raster/qgsrasterlayerproperties.cpp +++ b/src/gui/raster/qgsrasterlayerproperties.cpp @@ -816,6 +816,9 @@ void QgsRasterLayerProperties::sync() mInvertColorsCheck->setChecked( hueSaturationFilter->invertColors() ); } + // Resampling + mResamplingUtils.refreshWidgetsFromLayer(); + mRefreshSettingsWidget->syncToLayer(); QgsDebugMsgLevel( QStringLiteral( "populate general tab" ), 3 ); From 2e3be25c72ff0baeb9f7109cc30d35fab5055f7f Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Tue, 21 Jan 2025 13:25:21 +0000 Subject: [PATCH 47/81] remove option to set layer name from WMS, WFS and delimited text pages (refs #28857) --- .../qgsdelimitedtextsourceselect.cpp | 18 +- src/providers/wfs/qgswfssourceselect.cpp | 6 - src/providers/wms/qgswmssourceselect.cpp | 13 +- src/ui/qgsdelimitedtextsourceselectbase.ui | 104 +++----- src/ui/qgswfssourceselectbase.ui | 228 ++++++++---------- src/ui/qgswmssourceselectbase.ui | 22 +- 6 files changed, 156 insertions(+), 235 deletions(-) diff --git a/src/providers/delimitedtext/qgsdelimitedtextsourceselect.cpp b/src/providers/delimitedtext/qgsdelimitedtextsourceselect.cpp index 144ae0edfaf53..ad4254b285c6a 100644 --- a/src/providers/delimitedtext/qgsdelimitedtextsourceselect.cpp +++ b/src/providers/delimitedtext/qgsdelimitedtextsourceselect.cpp @@ -67,7 +67,6 @@ QgsDelimitedTextSourceSelect::QgsDelimitedTextSourceSelect( QWidget *parent, Qt: mBooleanFalse->setEnabled( !mBooleanTrue->text().isEmpty() ); updateFieldsAndEnable(); - connect( txtLayerName, &QLineEdit::textChanged, this, &QgsDelimitedTextSourceSelect::enableAccept ); connect( cmbEncoding, static_cast( &QComboBox::currentIndexChanged ), this, &QgsDelimitedTextSourceSelect::updateFieldsAndEnable ); connect( delimiterCSV, &QAbstractButton::toggled, this, &QgsDelimitedTextSourceSelect::updateFieldsAndEnable ); @@ -119,12 +118,6 @@ QgsDelimitedTextSourceSelect::QgsDelimitedTextSourceSelect( QWidget *parent, Qt: void QgsDelimitedTextSourceSelect::addButtonClicked() { // The following conditions should not be hit! OK will not be enabled... - if ( txtLayerName->text().isEmpty() ) - { - QMessageBox::warning( this, tr( "No layer name" ), tr( "Please enter a layer name before adding the layer to the map" ) ); - txtLayerName->setFocus(); - return; - } if ( delimiterChars->isChecked() ) { if ( selectedChars().isEmpty() ) @@ -159,17 +152,17 @@ void QgsDelimitedTextSourceSelect::addButtonClicked() saveSettings(); saveSettingsForFile( mFileWidget->filePath() ); + const QString layerName = QFileInfo( mFileWidget->filePath() ).completeBaseName(); // add the layer to the map Q_NOWARN_DEPRECATED_PUSH - emit addVectorLayer( datasourceUrl, txtLayerName->text() ); + emit addVectorLayer( datasourceUrl, layerName ); Q_NOWARN_DEPRECATED_POP - emit addLayer( Qgis::LayerType::Vector, datasourceUrl, txtLayerName->text(), QStringLiteral( "delimitedtext" ) ); + emit addLayer( Qgis::LayerType::Vector, datasourceUrl, layerName, QStringLiteral( "delimitedtext" ) ); // clear the file and layer name show something has happened, ready for another file mFileWidget->setFilePath( QString() ); - txtLayerName->setText( QString() ); if ( widgetMode() == QgsProviderRegistry::WidgetMode::Standalone ) { @@ -722,7 +715,6 @@ void QgsDelimitedTextSourceSelect::updateFileName() settings.setValue( mSettingsKey + "/text_path", finfo.path() ); } - txtLayerName->setText( finfo.completeBaseName() ); loadSettingsForFile( filename ); updateFieldsAndEnable(); } @@ -748,10 +740,6 @@ bool QgsDelimitedTextSourceSelect::validate() { message = tr( "File %1 does not exist" ).arg( mFileWidget->filePath() ); } - else if ( txtLayerName->text().isEmpty() ) - { - message = tr( "Please enter a layer name" ); - } else if ( delimiterChars->isChecked() && selectedChars().isEmpty() ) { message = tr( "At least one delimiter character must be specified" ); diff --git a/src/providers/wfs/qgswfssourceselect.cpp b/src/providers/wfs/qgswfssourceselect.cpp index d5b899c4a4e65..33f5e874f79db 100644 --- a/src/providers/wfs/qgswfssourceselect.cpp +++ b/src/providers/wfs/qgswfssourceselect.cpp @@ -95,7 +95,6 @@ QgsWFSSourceSelect::QgsWFSSourceSelect( QWidget *parent, Qt::WindowFlags fl, Qgs QgsSettings settings; QgsDebugMsgLevel( QStringLiteral( "restoring settings" ), 3 ); - cbxUseTitleLayerName->setChecked( settings.value( QStringLiteral( "Windows/WFSSourceSelect/UseTitleLayerName" ), false ).toBool() ); cbxFeatureCurrentViewExtent->setChecked( settings.value( QStringLiteral( "Windows/WFSSourceSelect/FeatureCurrentViewExtent" ), true ).toBool() ); mHoldDialogOpen->setChecked( settings.value( QStringLiteral( "Windows/WFSSourceSelect/HoldDialogOpen" ), false ).toBool() ); @@ -122,7 +121,6 @@ QgsWFSSourceSelect::~QgsWFSSourceSelect() QgsSettings settings; QgsDebugMsgLevel( QStringLiteral( "saving settings" ), 3 ); - settings.setValue( QStringLiteral( "Windows/WFSSourceSelect/UseTitleLayerName" ), cbxUseTitleLayerName->isChecked() ); settings.setValue( QStringLiteral( "Windows/WFSSourceSelect/FeatureCurrentViewExtent" ), cbxFeatureCurrentViewExtent->isChecked() ); settings.setValue( QStringLiteral( "Windows/WFSSourceSelect/HoldDialogOpen" ), mHoldDialogOpen->isChecked() ); @@ -533,10 +531,6 @@ void QgsWFSSourceSelect::addButtonClicked() QString titleName = mModel->item( row, MODEL_IDX_TITLE )->text(); //WFS type name title for layer name (if option is set) QString sql = mModel->item( row, MODEL_IDX_SQL )->text(); //optional SqL specified by user QString layerName = typeName; - if ( cbxUseTitleLayerName->isChecked() && !titleName.isEmpty() ) - { - layerName = titleName; - } QgsDebugMsgLevel( "Layer " + typeName + " SQL is " + sql, 3 ); mUri = QgsWFSDataSourceURI::build( connection.uri().uri( false ), typeName, pCrsString, isOapif() ? QString() : sql, isOapif() ? sql : QString(), cbxFeatureCurrentViewExtent->isChecked() ); diff --git a/src/providers/wms/qgswmssourceselect.cpp b/src/providers/wms/qgswmssourceselect.cpp index 81bed8c9588fa..ecf12e42a4938 100644 --- a/src/providers/wms/qgswmssourceselect.cpp +++ b/src/providers/wms/qgswmssourceselect.cpp @@ -78,9 +78,6 @@ QgsWMSSourceSelect::QgsWMSSourceSelect( QWidget *parent, Qt::WindowFlags fl, Qgs connect( mLayersFilterLineEdit, &QgsFilterLineEdit::textChanged, this, &QgsWMSSourceSelect::filterLayers ); connect( mTilesetsFilterLineEdit, &QgsFilterLineEdit::textChanged, this, &QgsWMSSourceSelect::filterTiles ); - connect( mLoadLayersIndividuallyCheckBox, &QCheckBox::toggled, leLayerName, &QLineEdit::setDisabled ); - - leLayerName->setDisabled( mLoadLayersIndividuallyCheckBox->isChecked() ); // Creates and connects standard ok/apply buttons setupButtons( buttonBox ); @@ -651,9 +648,9 @@ void QgsWMSSourceSelect::addButtonClicked() uri.setParam( QStringLiteral( "styles" ), styles ); Q_NOWARN_DEPRECATED_PUSH - emit addRasterLayer( uri.encodedUri(), leLayerName->text().isEmpty() ? titles.join( QLatin1Char( '/' ) ) : leLayerName->text(), QStringLiteral( "wms" ) ); + emit addRasterLayer( uri.encodedUri(), titles.join( QLatin1Char( '/' ) ), QStringLiteral( "wms" ) ); Q_NOWARN_DEPRECATED_POP - emit addLayer( Qgis::LayerType::Raster, uri.encodedUri(), leLayerName->text().isEmpty() ? titles.join( QLatin1Char( '/' ) ) : leLayerName->text(), QStringLiteral( "wms" ) ); + emit addLayer( Qgis::LayerType::Raster, uri.encodedUri(), titles.join( QLatin1Char( '/' ) ), QStringLiteral( "wms" ) ); } } @@ -1043,19 +1040,13 @@ void QgsWMSSourceSelect::updateButtons() QString tileLayerName = item->data( Qt::UserRole + 5 ).toString(); if ( tileLayerName.isEmpty() ) tileLayerName = item->data( Qt::UserRole + 0 ).toString(); - leLayerName->setText( tileLayerName ); } else { QStringList layers, styles, titles; collectSelectedLayers( layers, styles, titles ); - leLayerName->setText( titles.join( QLatin1Char( '/' ) ) ); } } - else - { - leLayerName->setText( "" ); - } } diff --git a/src/ui/qgsdelimitedtextsourceselectbase.ui b/src/ui/qgsdelimitedtextsourceselectbase.ui index 5e134aeb5e0ac..44c43ace64151 100644 --- a/src/ui/qgsdelimitedtextsourceselectbase.ui +++ b/src/ui/qgsdelimitedtextsourceselectbase.ui @@ -79,32 +79,6 @@ 0 - - - - - 0 - 0 - - - - Layer name - - - - - - - - 0 - 0 - - - - Name to display in the map legend - - - @@ -121,7 +95,7 @@ Select the file encoding - QComboBox::InsertAtTop + QComboBox::InsertPolicy::InsertAtTop @@ -145,7 +119,7 @@ - QFrame::NoFrame + QFrame::Shape::NoFrame true @@ -155,8 +129,8 @@ 0 0 - 703 - 647 + 698 + 655 @@ -179,14 +153,14 @@ 0 - + 0 0 - + File Format @@ -297,10 +271,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -332,7 +306,7 @@ Escape - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter txtEscapeChars @@ -348,10 +322,10 @@ - Quote + &Quote - Qt::AlignJustify|Qt::AlignVCenter + Qt::AlignmentFlag::AlignJustify|Qt::AlignmentFlag::AlignVCenter txtQuoteChars @@ -497,7 +471,7 @@ Others - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter txtDelimiterOther @@ -544,10 +518,10 @@ - QFrame::StyledPanel + QFrame::Shape::StyledPanel - QFrame::Raised + QFrame::Shadow::Raised @@ -603,14 +577,14 @@ - + 0 0 - + Record and Fields Options @@ -791,14 +765,14 @@ - + 0 0 - + Geometry Definition @@ -942,7 +916,7 @@ X field - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter cmbXField @@ -1246,7 +1220,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -1262,14 +1236,14 @@ - + 0 0 - + Layer Settings @@ -1370,7 +1344,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -1411,7 +1385,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -1441,10 +1415,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QDialogButtonBox::Help + QDialogButtonBox::StandardButton::Help @@ -1452,9 +1426,21 @@ + + QgsScrollArea + QScrollArea +
qgsscrollarea.h
+ 1 +
+ + QgsProjectionSelectionWidget + QWidget +
qgsprojectionselectionwidget.h
+ 1 +
QgsCollapsibleGroupBox - QGroupBox + QWidget
qgscollapsiblegroupbox.h
1
@@ -1468,20 +1454,8 @@ QWidget
qgsfilewidget.h
- - QgsProjectionSelectionWidget - QWidget -
qgsprojectionselectionwidget.h
-
- - QgsScrollArea - QScrollArea -
qgsscrollarea.h
- 1 -
- txtLayerName cmbEncoding scrollArea delimiterCSV diff --git a/src/ui/qgswfssourceselectbase.ui b/src/ui/qgswfssourceselectbase.ui index 6f16d2cc2b42e..c64e31601015f 100644 --- a/src/ui/qgswfssourceselectbase.ui +++ b/src/ui/qgswfssourceselectbase.ui @@ -14,105 +14,50 @@ Add WFS Layer from a Server - - - - Coordinate Reference System + + + + Keep dialog open - - - 6 - - - 9 - - - 9 - - - 9 - - - 9 - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 441 - 23 - - - - - - - - false - - - Change… - - - - - - - - - - Use title for layer name - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Keep dialog open - - - - + + + + true + + + + + - - - - Qt::Horizontal + + + + QAbstractItemView::EditTrigger::NoEditTriggers - - QDialogButtonBox::Help + + true + + + QAbstractItemView::SelectionMode::ExtendedSelection + + + true + + + true + + + + + + + Only request features overlapping the view extent - + Server Connections @@ -175,10 +120,10 @@ - Qt::Horizontal + Qt::Orientation::Horizontal - QSizePolicy::Expanding + QSizePolicy::Policy::Expanding @@ -213,45 +158,76 @@
- - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::ExtendedSelection - - - true - - - true - - - - - - - Only request features overlapping the view extent - - - - - - - true + + + + Qt::Orientation::Horizontal - - + + QDialogButtonBox::StandardButton::Help + + + + Coordinate Reference System + + + + 6 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + + + + + + + Qt::Orientation::Horizontal + + + QSizePolicy::Policy::Expanding + + + + 441 + 23 + + + + + + + + false + + + Change… + + + + + + @@ -270,8 +246,6 @@ btnLoad btnSave treeView - cbxUseTitleLayerName - mHoldDialogOpen cbxFeatureCurrentViewExtent btnChangeSpatialRefSys diff --git a/src/ui/qgswmssourceselectbase.ui b/src/ui/qgswmssourceselectbase.ui index 4591e4ebe542d..f1c4a180c01c3 100644 --- a/src/ui/qgswmssourceselectbase.ui +++ b/src/ui/qgswmssourceselectbase.ui @@ -39,14 +39,14 @@ - QDialogButtonBox::Help + QDialogButtonBox::StandardButton::Help - QFrame::NoFrame + QFrame::Shape::NoFrame true @@ -57,7 +57,7 @@ 0 0 744 - 639 + 647 @@ -142,7 +142,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -256,7 +256,7 @@ - Request step size + Re&quest step size mTileWidth @@ -280,7 +280,7 @@ - Qt::StrongFocus + Qt::FocusPolicy::StrongFocus @@ -303,7 +303,7 @@ - QAbstractItemView::ExtendedSelection + QAbstractItemView::SelectionMode::ExtendedSelection true @@ -380,7 +380,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -462,10 +462,10 @@ true - QAbstractItemView::SingleSelection + QAbstractItemView::SelectionMode::SingleSelection - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows false @@ -514,7 +514,7 @@ - Layer name + QGIS layer name leLayerName From 9f7f9d70bcec041a42675939935fce4bfac12b70 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Wed, 29 Jan 2025 10:02:24 +0000 Subject: [PATCH 48/81] remove unused variable --- src/providers/wfs/qgswfssourceselect.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/providers/wfs/qgswfssourceselect.cpp b/src/providers/wfs/qgswfssourceselect.cpp index 33f5e874f79db..06a3706f87a39 100644 --- a/src/providers/wfs/qgswfssourceselect.cpp +++ b/src/providers/wfs/qgswfssourceselect.cpp @@ -527,9 +527,8 @@ void QgsWFSSourceSelect::addButtonClicked() continue; } int row = idx.row(); - QString typeName = mModel->item( row, MODEL_IDX_NAME )->text(); //WFS repository's name for layer - QString titleName = mModel->item( row, MODEL_IDX_TITLE )->text(); //WFS type name title for layer name (if option is set) - QString sql = mModel->item( row, MODEL_IDX_SQL )->text(); //optional SqL specified by user + QString typeName = mModel->item( row, MODEL_IDX_NAME )->text(); //WFS repository's name for layer + QString sql = mModel->item( row, MODEL_IDX_SQL )->text(); //optional SqL specified by user QString layerName = typeName; QgsDebugMsgLevel( "Layer " + typeName + " SQL is " + sql, 3 ); From 5158569a54b20b06d443e54e378d566b5537e1a3 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 10:06:12 +1000 Subject: [PATCH 49/81] Remove an extraneous setting of layer scope for vectors We already have set the layer scope for ALL layer types in the map renderer job preparation, so there's no need to add another layer scope in the vector layer renderer Refs #60112 --- src/core/vector/qgsvectorlayerrenderer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/vector/qgsvectorlayerrenderer.cpp b/src/core/vector/qgsvectorlayerrenderer.cpp index 2e682ead38b12..34afa9f29a0d7 100644 --- a/src/core/vector/qgsvectorlayerrenderer.cpp +++ b/src/core/vector/qgsvectorlayerrenderer.cpp @@ -171,8 +171,6 @@ QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer *layer, QgsRender // set editing vertex markers style (main renderer only) mRenderer->setVertexMarkerAppearance( mVertexMarkerStyle, mVertexMarkerSize ); } - if ( !mNoSetLayerExpressionContext ) - renderContext()->expressionContext() << QgsExpressionContextUtils::layerScope( layer ); for ( const std::unique_ptr< QgsFeatureRenderer > &renderer : mRenderers ) { From 1bdce04cba5db75bfbf44275477a95af8df607e2 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 09:36:09 +1000 Subject: [PATCH 50/81] Simplify cmake condition --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40bcbb956a1ac..26511c30a62c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_AUTORCC ON) # set path to additional CMake modules set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) # POLICIES -if(NOT "${CMAKE_VERSION}" VERSION_LESS "3.27") +if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.27") # include(Dart) still used, as is the "Experimental" target cmake_policy(SET CMP0145 OLD) endif() From 3e50833349317b2cde5df759e11eb2c67102f8ff Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 09:37:00 +1000 Subject: [PATCH 51/81] Only include Dart when push to cdash is enabled It's only used for cdash submission --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 26511c30a62c0..5898713e3933e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -695,8 +695,10 @@ if (ENABLE_TESTS) set (PUSH_TO_CDASH FALSE CACHE BOOL "Determines whether test results should be pushed to CDASH site") set(QT_USE_QTTEST TRUE) enable_testing() - # Adds some testing specific build targets e.g. make Experimental - include(Dart) + if (PUSH_TO_CDASH) + # Adds some testing specific build targets e.g. make Experimental + include(Dart) + endif() # Additional test configuration options e.g. max upload size of test report configure_file( "${CMAKE_SOURCE_DIR}/cmake_templates/CTestCustom.cmake.in" From 096d6d0b58a971e91db7eb7092817d3ab19a6eb8 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 09:37:42 +1000 Subject: [PATCH 52/81] Remove unused/unmaintained jenkins_run script --- scripts/jenkins_run.sh | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100755 scripts/jenkins_run.sh diff --git a/scripts/jenkins_run.sh b/scripts/jenkins_run.sh deleted file mode 100755 index c9237e8497d83..0000000000000 --- a/scripts/jenkins_run.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -if [ -d build ] -then - rm -rf build -fi - -mkdir build -cd build || exit -cmake .. -#xvfb-run --auto-servernum --server-num=1 --server-args="-screen 0 1024x768x24" make Experimental || true -make Experimental || true -#TRES=0 -#ctest -T test --no-compress-output || true -if [ -f Testing/TAG ] ; then - xsltproc ../tests/ctest2junix.xsl Testing/$(head -n 1 < Testing/TAG)/Test.xml > CTestResults.xml -fi From 7a0e929ca7275d81e9aae29ae9a14882b071d517 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 09:39:46 +1000 Subject: [PATCH 53/81] Remove unused script for listing pull requests --- scripts/listpulls.pl | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 scripts/listpulls.pl diff --git a/scripts/listpulls.pl b/scripts/listpulls.pl deleted file mode 100644 index 39f4b78d3c104..0000000000000 --- a/scripts/listpulls.pl +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env perl - -use strict; -use warnings; - -use JSON; -use LWP::UserAgent; - -my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 }); -my $res = $ua->get( "https://api.github.com/repos/qgis/qgis/pulls" ); - -die "pull request retrieval failed: " . $res->status_line unless $res->is_success; - -my %assigned; - -printf "%5s %-16s %s\n", "#", "Assignee", "Title"; -foreach my $pull ( sort { $a->{number} <=> $b->{number} } @{ JSON::from_json( $res->decoded_content ) } ) { - my $assignee = $pull->{assignee}->{login}; - $assignee = "" unless defined $assignee; - - push @{ $assigned{$assignee} }, $pull->{number}; - - printf "%5d %-16s %s\n", $pull->{number}, $assignee || "", $pull->{title}; -} - -print "\nASSIGNMENTS:\n"; - -foreach my $assignee ( sort keys %assigned ) { - printf "%-22s %s\n", $assignee || "unassigned", join( ", ", sort { $a <=> $b } @{ $assigned{$assignee} } ); -} From 68d29e9de39a6f03d5714e323bef55c9322bdc20 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 09:41:23 +1000 Subject: [PATCH 54/81] Remove scripts/remove_non_svn_files.sh --- scripts/remove_non_svn_files.sh | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 scripts/remove_non_svn_files.sh diff --git a/scripts/remove_non_svn_files.sh b/scripts/remove_non_svn_files.sh deleted file mode 100644 index 792cfec9351bd..0000000000000 --- a/scripts/remove_non_svn_files.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -########################################################################### -# remove_non_svn_files.sh -# --------------------- -# Date : August 2008 -# Copyright : (C) 2008 by Tim Sutton -# Email : tim at kartoza 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. # -# # -########################################################################### - - -# -# A simple script to get rid of files that are not -# managed by svn. It will request confirmation before -# deleting each file. -# - -for FILE in $(svn status |grep "^?" | awk '{print $2}');do rm -i -r $FILE; done From 8977aac5e505c319d1153d19afd0cde925ad2f2b Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 09:42:41 +1000 Subject: [PATCH 55/81] Remove unused sipdiff script --- scripts/sipdiff | 67 ------------------------------------------------- 1 file changed, 67 deletions(-) delete mode 100755 scripts/sipdiff diff --git a/scripts/sipdiff b/scripts/sipdiff deleted file mode 100755 index 9994a0d903aaa..0000000000000 --- a/scripts/sipdiff +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bash - -DIR=$(git rev-parse --show-toplevel) - -# ARGUMENTS -SIPIFY=NO -while getopts ":s" opt; do - case $opt in - s) - # sipify header - SIPIFY=YES - ;; - \?) - echo "Invalid option: -$OPTARG" >&2 - exit 1 - ;; - esac -done -shift $(($OPTIND - 1)) - - - -for file in $*; do - d=${file#*/} - d=${d%/*} - f=${file##*/} - f=${f%.*} - header="src/$d/$f.h" - - if ! grep -Fxq "$d/$f.sip" python/auto_sip.blocklist; then - echo -e "\033[0;31m$d/$f.sip is an automatically generated SIP file\033[0m" - echo -e " g) \x1B[4mg\x1B[0menerate the SIP file \033[0;32m./scripts/sipify.pl $header > python/$d/$f.sip\033[0m" - echo -e " s) \x1B[4ms\x1B[0mhow the diff" - SHOW=NO - while read -n 1 n; do - echo "" - case $n in - g) - echo "Generating the SIP file ..." - pushd ${DIR} - ./scripts/sipify.pl $header > python/$d/$f.sip - popd - break - ;; - s) - SHOW=YES - break - ;; - *) - invalid option - ;; - esac - done - if [[ $SHOW =~ NO ]]; then - continue - fi - fi - - if [[ $SIPIFY =~ YES ]]; then - tempfile=$(mktemp ${DIR}/${f}XXXX --suffix=.h) - ${DIR}/scripts/sipify.pl ${DIR}/$header > $tempfile - else - tempfile=$header - fi - vimdiff $tempfile python/$d/$f.sip - -done From 033512a8d1d4d3b2585fee9d169c49354d11d662 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 09:43:36 +1000 Subject: [PATCH 56/81] Remove unused widgets_tree.py script --- scripts/widgets_tree.py | 204 ---------------------------------------- 1 file changed, 204 deletions(-) delete mode 100644 scripts/widgets_tree.py diff --git a/scripts/widgets_tree.py b/scripts/widgets_tree.py deleted file mode 100644 index 10a2b4efe0243..0000000000000 --- a/scripts/widgets_tree.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env python3 - -""" -*************************************************************************** - widgets_tree.py - --------------------- - Date : May 2011 - Copyright : (C) 2011 by Martin Dobias - Email : wonder dot sk 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. * -* * -*************************************************************************** -""" - -__author__ = "Martin Dobias" -__date__ = "May 2011" -__copyright__ = "(C) 2011, Martin Dobias" - -""" -Reads .ui files from ../src/ui/ directory and write to stdout an XML describing -widgets tree. - -Python bindings must be compiled and in PYTHONPATH - -QGIS libraries must be in LD_LIBRARY_PATH - -Output should go to ../resources/customization.xml - -""" - -import glob -import os -import sys - -# qwt_plot is missing somehow but it may depend on installed packages -from qgis.PyQt import Qwt5 as qwt_plot -from qgis.PyQt.QtWidgets import ( - QCheckBox, - QComboBox, - QDateEdit, - QDateTimeEdit, - QDial, - QDialog, - QDialogButtonBox, - QGroupBox, - QLabel, - QLCDNumber, - QLineEdit, - QListView, - QProgressBar, - QPushButton, - QRadioButton, - QScrollArea, - QScrollBar, - QSlider, - QSpinBox, - QStackedWidget, - QTableView, - QTabWidget, - QTextBrowser, - QTextEdit, - QTimeEdit, - QWidget, -) -from qgis.PyQt.QtXml import QDomDocument -from qgis.PyQt.uic import loadUi - -sys.modules["qwt_plot"] = qwt_plot - -# loadUi is looking for custom widget in module which is lowercase version of -# the class, which do not exist (AFAIK) -> preload them, problems anyway: -# missing in gui: QgsColorRampComboBox, QgsRendererRulesTreeWidget, -# QgsRendererRulesTreeWidget -# and QgsProjectionSelector cannot open db file -from qgis import gui - -for m in [ - "qgscolorbutton", - "qgscolorrampcombobox", - "qgsprojectionselector", - "qgslabelpreview", - "qgsrulebasedrendererwidget", - "qgscollapsiblegroupbox", - "qgsblendmodecombobox", - "qgsexpressionbuilderwidget", - "qgsrasterformatsaveoptionswidget", - "qgsrasterpyramidsoptionswidget", - "qgsscalecombobox", - "qgsfilterlineedit", - "qgsdualview", -]: - sys.modules[m] = gui - - -class UiInspector: - - def __init__(self): - self.ui_dir = os.path.abspath( - os.path.join(os.path.dirname(__file__), "../src/ui/*.ui") - ) - self.printMsg("Loading UI files " + self.ui_dir) - # list of widget classes we want to follow - self.follow = [ - QWidget, - QDialog, - QCheckBox, - QComboBox, - QDial, - QPushButton, - QLabel, - QLCDNumber, - QLineEdit, - QRadioButton, - QScrollBar, - QSlider, - QSpinBox, - QTextEdit, - QDateEdit, - QTimeEdit, - QDateTimeEdit, - QListView, - QProgressBar, - QTableView, - QTabWidget, - QTextBrowser, - QDialogButtonBox, - QScrollArea, - QGroupBox, - QStackedWidget, - ] - - def printMsg(self, msg): - sys.stderr.write(msg + "\n") - - def widgetXml(self, element, widget, level=0, label=None): - # print tostring ( element ) - # self.printMsg ( "class: " + str( type ( widget ) ) ) - # self.printMsg ( "objectName: " + widget.objectName() ) - # self.printMsg ( "windowTitle: " + widget.windowTitle() ) - - if not widget.objectName(): - return - - lab = label - if hasattr(widget, "text"): - lab = widget.text() - if widget.windowTitle(): - label = widget.windowTitle() - if not lab: - lab = "" - - subElement = self.doc.createElement("widget") - subElement.setAttribute("class", widget.__class__.__name__) - subElement.setAttribute("objectName", widget.objectName()) - subElement.setAttribute("label", lab) - element.appendChild(subElement) - - # print str ( widget.children () ) - # tab widget label is stored in QTabWidget->QTabBarPrivate->tabList->QTab .. - if type(widget) in [QTabWidget]: - children = list( - {"widget": widget.widget(i), "label": widget.tabText(i)} - for i in range(0, widget.count()) - ) - else: - children = list({"widget": c, "label": None} for c in widget.children()) - for child in children: - w = child["widget"] - if w.isWidgetType() and (type(w) in self.follow): - self.widgetXml(subElement, w, level + 1, child["label"]) - - def xml(self): - self.doc = QDomDocument() - element = self.doc.createElement("qgiswidgets") - self.doc.appendChild(element) - for p in glob.glob(self.ui_dir): - self.printMsg("Loading " + p) - # qgsrasterlayerpropertiesbase.ui is giving: No module named qwt_plot - try: - widget = loadUi(p) - # print dir ( ui ) - self.widgetXml(element, widget) - except Exception as e: - self.printMsg(str(e)) - - return self.doc.toString(2) - - -if __name__ == "__main__": - from qgis.PyQt.QtCore import QApplication - - app = QApplication(sys.argv) # required by loadUi - inspector = UiInspector() - xml = inspector.xml() - sys.stdout.write(xml) - sys.stdout.flush() - - del app - sys.exit(0) From 3ed5714efcabcf9da124d1f157243cf3f767d8c6 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 11:58:46 +1000 Subject: [PATCH 57/81] Fix incorrect QGISDEBUG definition check --- src/core/pointcloud/qgscopcpointcloudindex.cpp | 2 +- src/core/pointcloud/qgseptpointcloudindex.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/pointcloud/qgscopcpointcloudindex.cpp b/src/core/pointcloud/qgscopcpointcloudindex.cpp index 24bd1bd602443..ce98c4bb16254 100644 --- a/src/core/pointcloud/qgscopcpointcloudindex.cpp +++ b/src/core/pointcloud/qgscopcpointcloudindex.cpp @@ -134,7 +134,7 @@ bool QgsCopcPointCloudIndex::loadSchema( QgsLazInfo &lazInfo ) // TODO: Rounding? mSpan = mRootBounds.width() / mCopcInfoVlr.spacing; -#ifdef QGIS_DEBUG +#ifdef QGISDEBUG double dx = xmax - xmin, dy = ymax - ymin, dz = zmax - zmin; QgsDebugMsgLevel( QStringLiteral( "lvl0 node size in CRS units: %1 %2 %3" ).arg( dx ).arg( dy ).arg( dz ), 2 ); // all dims should be the same QgsDebugMsgLevel( QStringLiteral( "res at lvl0 %1" ).arg( dx / mSpan ), 2 ); diff --git a/src/core/pointcloud/qgseptpointcloudindex.cpp b/src/core/pointcloud/qgseptpointcloudindex.cpp index fb2c8f22fd929..53343554dd2b9 100644 --- a/src/core/pointcloud/qgseptpointcloudindex.cpp +++ b/src/core/pointcloud/qgseptpointcloudindex.cpp @@ -358,7 +358,7 @@ bool QgsEptPointCloudIndex::loadSchema( const QByteArray &dataJson ) mRootBounds = QgsBox3D( xmin, ymin, zmin, xmax, ymax, zmax ); -#ifdef QGIS_DEBUG +#ifdef QGISDEBUG double dx = xmax - xmin, dy = ymax - ymin, dz = zmax - zmin; QgsDebugMsgLevel( QStringLiteral( "lvl0 node size in CRS units: %1 %2 %3" ).arg( dx ).arg( dy ).arg( dz ), 2 ); // all dims should be the same QgsDebugMsgLevel( QStringLiteral( "res at lvl0 %1" ).arg( dx / mSpan ), 2 ); From 4a3f5d5d5c757ad565af898747ec0e3eb2b58397 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 12:39:28 +1000 Subject: [PATCH 58/81] [sensorthings] Remove option for basic authentication This is not supported by the provider, only authentication config is supported Fixes #59721 --- .../gui/auto_generated/auth/qgsauthsettingswidget.sip.in | 7 +++++++ .../gui/auto_generated/auth/qgsauthsettingswidget.sip.in | 7 +++++++ src/gui/auth/qgsauthsettingswidget.cpp | 6 ++++++ src/gui/auth/qgsauthsettingswidget.h | 7 +++++++ .../sensorthings/qgssensorthingsconnectionwidget.cpp | 3 +++ 5 files changed, 30 insertions(+) diff --git a/python/PyQt6/gui/auto_generated/auth/qgsauthsettingswidget.sip.in b/python/PyQt6/gui/auto_generated/auth/qgsauthsettingswidget.sip.in index 3d604f327b157..c6df7f3d0b2fe 100644 --- a/python/PyQt6/gui/auto_generated/auth/qgsauthsettingswidget.sip.in +++ b/python/PyQt6/gui/auto_generated/auth/qgsauthsettingswidget.sip.in @@ -39,6 +39,13 @@ from existing configs, or creating/removing them from auth database :param username: :param password: :param dataprovider: The key of the calling layer provider, if applicable +%End + + void removeBasicSettings(); +%Docstring +Removes the basic authentication tab from the widget. + +.. versionadded:: 3.42 %End void setWarningText( const QString &warningText ); diff --git a/python/gui/auto_generated/auth/qgsauthsettingswidget.sip.in b/python/gui/auto_generated/auth/qgsauthsettingswidget.sip.in index a7a969fa8c8aa..aebdcc09c56b9 100644 --- a/python/gui/auto_generated/auth/qgsauthsettingswidget.sip.in +++ b/python/gui/auto_generated/auth/qgsauthsettingswidget.sip.in @@ -39,6 +39,13 @@ from existing configs, or creating/removing them from auth database :param username: :param password: :param dataprovider: The key of the calling layer provider, if applicable +%End + + void removeBasicSettings(); +%Docstring +Removes the basic authentication tab from the widget. + +.. versionadded:: 3.42 %End void setWarningText( const QString &warningText ); diff --git a/src/gui/auth/qgsauthsettingswidget.cpp b/src/gui/auth/qgsauthsettingswidget.cpp index c49f11cd2c310..02bfe356e6cde 100644 --- a/src/gui/auth/qgsauthsettingswidget.cpp +++ b/src/gui/auth/qgsauthsettingswidget.cpp @@ -50,6 +50,12 @@ QgsAuthSettingsWidget::QgsAuthSettingsWidget( QWidget *parent, const QString &co updateConvertBtnState(); } +void QgsAuthSettingsWidget::removeBasicSettings() +{ + tabAuth->removeTab( tabAuth->indexOf( tabBasic ) ); + tabAuth->setCurrentIndex( tabAuth->indexOf( tabConfigurations ) ); +} + void QgsAuthSettingsWidget::setWarningText( const QString &warningText ) { lblWarning->setText( warningText ); diff --git a/src/gui/auth/qgsauthsettingswidget.h b/src/gui/auth/qgsauthsettingswidget.h index e3a422b3fc157..eadfdeccba9e0 100644 --- a/src/gui/auth/qgsauthsettingswidget.h +++ b/src/gui/auth/qgsauthsettingswidget.h @@ -62,6 +62,13 @@ class GUI_EXPORT QgsAuthSettingsWidget : public QWidget, private Ui::QgsAuthSett */ explicit QgsAuthSettingsWidget( QWidget *parent SIP_TRANSFERTHIS = nullptr, const QString &configId = QString(), const QString &username = QString(), const QString &password = QString(), const QString &dataprovider = QString() ); + /** + * Removes the basic authentication tab from the widget. + * + * \since QGIS 3.42 + */ + void removeBasicSettings(); + /** * \brief setWarningText set the text of the warning label * \param warningText the text of the warning label diff --git a/src/gui/providers/sensorthings/qgssensorthingsconnectionwidget.cpp b/src/gui/providers/sensorthings/qgssensorthingsconnectionwidget.cpp index e16b5409e2c97..c15dcf2d3a859 100644 --- a/src/gui/providers/sensorthings/qgssensorthingsconnectionwidget.cpp +++ b/src/gui/providers/sensorthings/qgssensorthingsconnectionwidget.cpp @@ -29,6 +29,9 @@ QgsSensorThingsConnectionWidget::QgsSensorThingsConnectionWidget( QWidget *paren connect( mEditUrl, &QLineEdit::textChanged, this, &QgsSensorThingsConnectionWidget::validate ); connect( mEditUrl, &QLineEdit::textChanged, this, &QgsSensorThingsConnectionWidget::changed ); + // only auth config supported, not basic auth + mAuthSettings->removeBasicSettings(); + connect( mAuthSettings, &QgsAuthSettingsWidget::configIdChanged, this, &QgsSensorThingsConnectionWidget::changed ); connect( mAuthSettings, &QgsAuthSettingsWidget::usernameChanged, this, &QgsSensorThingsConnectionWidget::changed ); connect( mAuthSettings, &QgsAuthSettingsWidget::passwordChanged, this, &QgsSensorThingsConnectionWidget::changed ); From 65670a5e930b321bb00e7394f9bf9f56e70c1dd0 Mon Sep 17 00:00:00 2001 From: qgis-bot Date: Fri, 31 Jan 2025 07:14:22 +0000 Subject: [PATCH 59/81] =?UTF-8?q?auto=20sipify=20=F0=9F=8D=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/PyQt6/gui/class_map.yaml | 45 +++++++++++++++++---------------- python/gui/class_map.yaml | 45 +++++++++++++++++---------------- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/python/PyQt6/gui/class_map.yaml b/python/PyQt6/gui/class_map.yaml index a3efdf41aa370..909311102e09c 100644 --- a/python/PyQt6/gui/class_map.yaml +++ b/python/PyQt6/gui/class_map.yaml @@ -1022,28 +1022,29 @@ QgsAuthServersEditor.QgsAuthServersEditor: src/gui/auth/qgsauthserverseditor.h#L QgsAuthServersEditor.showEvent: src/gui/auth/qgsauthserverseditor.h#L69 QgsAuthServersEditor: src/gui/auth/qgsauthserverseditor.h#L33 QgsAuthSettingsWidget.QgsAuthSettingsWidget: src/gui/auth/qgsauthsettingswidget.h#L63 -QgsAuthSettingsWidget.btnConvertToEncryptedIsEnabled: src/gui/auth/qgsauthsettingswidget.h#L137 -QgsAuthSettingsWidget.configId: src/gui/auth/qgsauthsettingswidget.h#L106 -QgsAuthSettingsWidget.configIdChanged: src/gui/auth/qgsauthsettingswidget.h#L211 -QgsAuthSettingsWidget.configurationTabIsSelected: src/gui/auth/qgsauthsettingswidget.h#L178 -QgsAuthSettingsWidget.convertToEncrypted: src/gui/auth/qgsauthsettingswidget.h#L188 -QgsAuthSettingsWidget.dataprovider: src/gui/auth/qgsauthsettingswidget.h#L124 -QgsAuthSettingsWidget.formattedWarning: src/gui/auth/qgsauthsettingswidget.h#L131 -QgsAuthSettingsWidget.password: src/gui/auth/qgsauthsettingswidget.h#L94 -QgsAuthSettingsWidget.passwordChanged: src/gui/auth/qgsauthsettingswidget.h#L204 -QgsAuthSettingsWidget.setBasicText: src/gui/auth/qgsauthsettingswidget.h#L76 -QgsAuthSettingsWidget.setConfigId: src/gui/auth/qgsauthsettingswidget.h#L112 -QgsAuthSettingsWidget.setDataprovider: src/gui/auth/qgsauthsettingswidget.h#L118 -QgsAuthSettingsWidget.setPassword: src/gui/auth/qgsauthsettingswidget.h#L100 -QgsAuthSettingsWidget.setStorePasswordChecked: src/gui/auth/qgsauthsettingswidget.h#L160 -QgsAuthSettingsWidget.setStoreUsernameChecked: src/gui/auth/qgsauthsettingswidget.h#L153 -QgsAuthSettingsWidget.setUsername: src/gui/auth/qgsauthsettingswidget.h#L88 -QgsAuthSettingsWidget.setWarningText: src/gui/auth/qgsauthsettingswidget.h#L70 -QgsAuthSettingsWidget.showStoreCheckboxes: src/gui/auth/qgsauthsettingswidget.h#L146 -QgsAuthSettingsWidget.storePasswordIsChecked: src/gui/auth/qgsauthsettingswidget.h#L166 -QgsAuthSettingsWidget.storeUsernameIsChecked: src/gui/auth/qgsauthsettingswidget.h#L172 -QgsAuthSettingsWidget.username: src/gui/auth/qgsauthsettingswidget.h#L82 -QgsAuthSettingsWidget.usernameChanged: src/gui/auth/qgsauthsettingswidget.h#L197 +QgsAuthSettingsWidget.btnConvertToEncryptedIsEnabled: src/gui/auth/qgsauthsettingswidget.h#L144 +QgsAuthSettingsWidget.configId: src/gui/auth/qgsauthsettingswidget.h#L113 +QgsAuthSettingsWidget.configIdChanged: src/gui/auth/qgsauthsettingswidget.h#L218 +QgsAuthSettingsWidget.configurationTabIsSelected: src/gui/auth/qgsauthsettingswidget.h#L185 +QgsAuthSettingsWidget.convertToEncrypted: src/gui/auth/qgsauthsettingswidget.h#L195 +QgsAuthSettingsWidget.dataprovider: src/gui/auth/qgsauthsettingswidget.h#L131 +QgsAuthSettingsWidget.formattedWarning: src/gui/auth/qgsauthsettingswidget.h#L138 +QgsAuthSettingsWidget.password: src/gui/auth/qgsauthsettingswidget.h#L101 +QgsAuthSettingsWidget.passwordChanged: src/gui/auth/qgsauthsettingswidget.h#L211 +QgsAuthSettingsWidget.removeBasicSettings: src/gui/auth/qgsauthsettingswidget.h#L70 +QgsAuthSettingsWidget.setBasicText: src/gui/auth/qgsauthsettingswidget.h#L83 +QgsAuthSettingsWidget.setConfigId: src/gui/auth/qgsauthsettingswidget.h#L119 +QgsAuthSettingsWidget.setDataprovider: src/gui/auth/qgsauthsettingswidget.h#L125 +QgsAuthSettingsWidget.setPassword: src/gui/auth/qgsauthsettingswidget.h#L107 +QgsAuthSettingsWidget.setStorePasswordChecked: src/gui/auth/qgsauthsettingswidget.h#L167 +QgsAuthSettingsWidget.setStoreUsernameChecked: src/gui/auth/qgsauthsettingswidget.h#L160 +QgsAuthSettingsWidget.setUsername: src/gui/auth/qgsauthsettingswidget.h#L95 +QgsAuthSettingsWidget.setWarningText: src/gui/auth/qgsauthsettingswidget.h#L77 +QgsAuthSettingsWidget.showStoreCheckboxes: src/gui/auth/qgsauthsettingswidget.h#L153 +QgsAuthSettingsWidget.storePasswordIsChecked: src/gui/auth/qgsauthsettingswidget.h#L173 +QgsAuthSettingsWidget.storeUsernameIsChecked: src/gui/auth/qgsauthsettingswidget.h#L179 +QgsAuthSettingsWidget.username: src/gui/auth/qgsauthsettingswidget.h#L89 +QgsAuthSettingsWidget.usernameChanged: src/gui/auth/qgsauthsettingswidget.h#L204 QgsAuthSettingsWidget: src/gui/auth/qgsauthsettingswidget.h#L35 QgsAuthSslConfigDialog.QgsAuthSslConfigDialog: src/gui/auth/qgsauthsslconfigwidget.h#L198 QgsAuthSslConfigDialog.accept: src/gui/auth/qgsauthsslconfigwidget.h#L204 diff --git a/python/gui/class_map.yaml b/python/gui/class_map.yaml index a3efdf41aa370..909311102e09c 100644 --- a/python/gui/class_map.yaml +++ b/python/gui/class_map.yaml @@ -1022,28 +1022,29 @@ QgsAuthServersEditor.QgsAuthServersEditor: src/gui/auth/qgsauthserverseditor.h#L QgsAuthServersEditor.showEvent: src/gui/auth/qgsauthserverseditor.h#L69 QgsAuthServersEditor: src/gui/auth/qgsauthserverseditor.h#L33 QgsAuthSettingsWidget.QgsAuthSettingsWidget: src/gui/auth/qgsauthsettingswidget.h#L63 -QgsAuthSettingsWidget.btnConvertToEncryptedIsEnabled: src/gui/auth/qgsauthsettingswidget.h#L137 -QgsAuthSettingsWidget.configId: src/gui/auth/qgsauthsettingswidget.h#L106 -QgsAuthSettingsWidget.configIdChanged: src/gui/auth/qgsauthsettingswidget.h#L211 -QgsAuthSettingsWidget.configurationTabIsSelected: src/gui/auth/qgsauthsettingswidget.h#L178 -QgsAuthSettingsWidget.convertToEncrypted: src/gui/auth/qgsauthsettingswidget.h#L188 -QgsAuthSettingsWidget.dataprovider: src/gui/auth/qgsauthsettingswidget.h#L124 -QgsAuthSettingsWidget.formattedWarning: src/gui/auth/qgsauthsettingswidget.h#L131 -QgsAuthSettingsWidget.password: src/gui/auth/qgsauthsettingswidget.h#L94 -QgsAuthSettingsWidget.passwordChanged: src/gui/auth/qgsauthsettingswidget.h#L204 -QgsAuthSettingsWidget.setBasicText: src/gui/auth/qgsauthsettingswidget.h#L76 -QgsAuthSettingsWidget.setConfigId: src/gui/auth/qgsauthsettingswidget.h#L112 -QgsAuthSettingsWidget.setDataprovider: src/gui/auth/qgsauthsettingswidget.h#L118 -QgsAuthSettingsWidget.setPassword: src/gui/auth/qgsauthsettingswidget.h#L100 -QgsAuthSettingsWidget.setStorePasswordChecked: src/gui/auth/qgsauthsettingswidget.h#L160 -QgsAuthSettingsWidget.setStoreUsernameChecked: src/gui/auth/qgsauthsettingswidget.h#L153 -QgsAuthSettingsWidget.setUsername: src/gui/auth/qgsauthsettingswidget.h#L88 -QgsAuthSettingsWidget.setWarningText: src/gui/auth/qgsauthsettingswidget.h#L70 -QgsAuthSettingsWidget.showStoreCheckboxes: src/gui/auth/qgsauthsettingswidget.h#L146 -QgsAuthSettingsWidget.storePasswordIsChecked: src/gui/auth/qgsauthsettingswidget.h#L166 -QgsAuthSettingsWidget.storeUsernameIsChecked: src/gui/auth/qgsauthsettingswidget.h#L172 -QgsAuthSettingsWidget.username: src/gui/auth/qgsauthsettingswidget.h#L82 -QgsAuthSettingsWidget.usernameChanged: src/gui/auth/qgsauthsettingswidget.h#L197 +QgsAuthSettingsWidget.btnConvertToEncryptedIsEnabled: src/gui/auth/qgsauthsettingswidget.h#L144 +QgsAuthSettingsWidget.configId: src/gui/auth/qgsauthsettingswidget.h#L113 +QgsAuthSettingsWidget.configIdChanged: src/gui/auth/qgsauthsettingswidget.h#L218 +QgsAuthSettingsWidget.configurationTabIsSelected: src/gui/auth/qgsauthsettingswidget.h#L185 +QgsAuthSettingsWidget.convertToEncrypted: src/gui/auth/qgsauthsettingswidget.h#L195 +QgsAuthSettingsWidget.dataprovider: src/gui/auth/qgsauthsettingswidget.h#L131 +QgsAuthSettingsWidget.formattedWarning: src/gui/auth/qgsauthsettingswidget.h#L138 +QgsAuthSettingsWidget.password: src/gui/auth/qgsauthsettingswidget.h#L101 +QgsAuthSettingsWidget.passwordChanged: src/gui/auth/qgsauthsettingswidget.h#L211 +QgsAuthSettingsWidget.removeBasicSettings: src/gui/auth/qgsauthsettingswidget.h#L70 +QgsAuthSettingsWidget.setBasicText: src/gui/auth/qgsauthsettingswidget.h#L83 +QgsAuthSettingsWidget.setConfigId: src/gui/auth/qgsauthsettingswidget.h#L119 +QgsAuthSettingsWidget.setDataprovider: src/gui/auth/qgsauthsettingswidget.h#L125 +QgsAuthSettingsWidget.setPassword: src/gui/auth/qgsauthsettingswidget.h#L107 +QgsAuthSettingsWidget.setStorePasswordChecked: src/gui/auth/qgsauthsettingswidget.h#L167 +QgsAuthSettingsWidget.setStoreUsernameChecked: src/gui/auth/qgsauthsettingswidget.h#L160 +QgsAuthSettingsWidget.setUsername: src/gui/auth/qgsauthsettingswidget.h#L95 +QgsAuthSettingsWidget.setWarningText: src/gui/auth/qgsauthsettingswidget.h#L77 +QgsAuthSettingsWidget.showStoreCheckboxes: src/gui/auth/qgsauthsettingswidget.h#L153 +QgsAuthSettingsWidget.storePasswordIsChecked: src/gui/auth/qgsauthsettingswidget.h#L173 +QgsAuthSettingsWidget.storeUsernameIsChecked: src/gui/auth/qgsauthsettingswidget.h#L179 +QgsAuthSettingsWidget.username: src/gui/auth/qgsauthsettingswidget.h#L89 +QgsAuthSettingsWidget.usernameChanged: src/gui/auth/qgsauthsettingswidget.h#L204 QgsAuthSettingsWidget: src/gui/auth/qgsauthsettingswidget.h#L35 QgsAuthSslConfigDialog.QgsAuthSslConfigDialog: src/gui/auth/qgsauthsslconfigwidget.h#L198 QgsAuthSslConfigDialog.accept: src/gui/auth/qgsauthsslconfigwidget.h#L204 From 1cf9734e5579bb8af3bbfa390df5c48aa90a5ff9 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 11:59:47 +1000 Subject: [PATCH 60/81] When a layer changes from non-spatial to spatial, update canvas layers If a layer changes data source then it may potentially change from a non-spatial layer to a spatial layer. Accordingly, listen out for this and trigger a canvas layer update whenever a layer's source changes. This ensures that ALL spatial layers are correctly visible in the canvas immediately after the source change triggers the spatial status change. Fixes #59723 --- src/gui/layertree/qgslayertreemapcanvasbridge.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/layertree/qgslayertreemapcanvasbridge.cpp b/src/gui/layertree/qgslayertreemapcanvasbridge.cpp index 4daf5814f43a7..2608c7e45e053 100644 --- a/src/gui/layertree/qgslayertreemapcanvasbridge.cpp +++ b/src/gui/layertree/qgslayertreemapcanvasbridge.cpp @@ -203,6 +203,7 @@ void QgsLayerTreeMapCanvasBridge::layersAdded( const QList &layer // if we are moving from zero valid layers to non-zero VALID layers, let's zoom to those data mCanvas->zoomToProjectExtent(); } + deferredSetCanvasLayers(); } ); } } From c42f86ff26535c9b88ac270da7555c951fb24818 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 31 Jan 2025 16:52:23 +0100 Subject: [PATCH 61/81] Add Raster Layer: do not include credentials in layer name Fixes #60292 --- src/app/layers/qgsapplayerhandling.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app/layers/qgsapplayerhandling.cpp b/src/app/layers/qgsapplayerhandling.cpp index 65c547a3fed72..622b97c92fb65 100644 --- a/src/app/layers/qgsapplayerhandling.cpp +++ b/src/app/layers/qgsapplayerhandling.cpp @@ -1134,8 +1134,6 @@ QList QgsAppLayerHandling::addGdalRasterLayers( const QStringList if ( QgsRasterLayer::isValidRasterFileName( uri, errMsg ) ) { - QFileInfo myFileInfo( uri ); - // set the layer name to the file base name unless provided explicitly QString layerName; const QVariantMap uriDetails = QgsProviderRegistry::instance()->decodeUri( QStringLiteral( "gdal" ), uri ); @@ -1145,7 +1143,7 @@ QList QgsAppLayerHandling::addGdalRasterLayers( const QStringList } else { - layerName = QgsProviderUtils::suggestLayerNameFromFilePath( uri ); + layerName = QgsProviderUtils::suggestLayerNameFromFilePath( uriDetails[QStringLiteral( "path" )].toString() ); } // try to create the layer @@ -1163,7 +1161,7 @@ QList QgsAppLayerHandling::addGdalRasterLayers( const QStringList //only allow one copy of a ai grid file to be loaded at a //time to prevent the user selecting all adfs in 1 dir which //actually represent 1 coverage, - + const QFileInfo myFileInfo( uriDetails[QStringLiteral( "path" )].toString() ); if ( myFileInfo.fileName().endsWith( QLatin1String( ".adf" ), Qt::CaseInsensitive ) ) { break; From 27a28461307594390146dbab25a180ad2b3e6ff5 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 11:12:36 +1000 Subject: [PATCH 62/81] [pal] Always iterate through labeled layers in original layer order Ensures that labeling solutions are deterministic --- src/core/pal/pal.cpp | 9 +++++++-- src/core/pal/pal.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/core/pal/pal.cpp b/src/core/pal/pal.cpp index dda39bd116bf1..83d3b4831238e 100644 --- a/src/core/pal/pal.cpp +++ b/src/core/pal/pal.cpp @@ -88,11 +88,16 @@ Layer *Pal::addLayer( QgsAbstractLabelProvider *provider, const QString &layerNa { mMutex.lock(); - Q_ASSERT( mLayers.find( provider ) == mLayers.end() ); +#ifdef QGISDEBUG + for ( const auto &it : mLayers ) + { + Q_ASSERT( it.first != provider ); + } +#endif std::unique_ptr< Layer > layer = std::make_unique< Layer >( provider, layerName, arrangement, defaultPriority, active, toLabel, this ); Layer *res = layer.get(); - mLayers.insert( std::pair>( provider, std::move( layer ) ) ); + mLayers.emplace_back( std::make_pair( provider, std::move( layer ) ) ); mMutex.unlock(); // cppcheck-suppress returnDanglingLifetime diff --git a/src/core/pal/pal.h b/src/core/pal/pal.h index 0f8a2192b351f..dc9c5991a5c77 100644 --- a/src/core/pal/pal.h +++ b/src/core/pal/pal.h @@ -279,7 +279,7 @@ namespace pal private: - std::unordered_map< QgsAbstractLabelProvider *, std::unique_ptr< Layer > > mLayers; + std::vector< std::pair< QgsAbstractLabelProvider *, std::unique_ptr< Layer > > > mLayers; QList< QgsAbstractLabelingEngineRule * > mRules; From 31df6fa2ace9b948edeeeadc0adc6ba57602fd07 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 12:52:10 +1000 Subject: [PATCH 63/81] [pal] reverse iterate through layers We want the highest layers in the layer tree to be handled first --- src/core/pal/pal.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/pal/pal.cpp b/src/core/pal/pal.cpp index 83d3b4831238e..e4548ca69e61e 100644 --- a/src/core/pal/pal.cpp +++ b/src/core/pal/pal.cpp @@ -163,13 +163,13 @@ std::unique_ptr Pal::extractProblem( const QgsRectangle &extent, const candidateProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Generating label candidates" ), QStringLiteral( "rendering" ) ); } - for ( const auto &it : mLayers ) + for ( auto it = mLayers.rbegin(); it != mLayers.rend(); ++it ) { index++; if ( feedback ) feedback->setProgress( index * step ); - Layer *layer = it.second.get(); + Layer *layer = it->second.get(); if ( !layer ) { // invalid layer name @@ -181,12 +181,12 @@ std::unique_ptr Pal::extractProblem( const QgsRectangle &extent, const continue; if ( feedback ) - feedback->emit candidateCreationAboutToBegin( it.first ); + feedback->emit candidateCreationAboutToBegin( it->first ); std::unique_ptr< QgsScopedRuntimeProfile > layerProfile; if ( context.flags() & Qgis::RenderContextFlag::RecordProfile ) { - layerProfile = std::make_unique< QgsScopedRuntimeProfile >( it.first->providerId(), QStringLiteral( "rendering" ) ); + layerProfile = std::make_unique< QgsScopedRuntimeProfile >( it->first->providerId(), QStringLiteral( "rendering" ) ); } // check for connected features with the same label text and join them @@ -338,7 +338,7 @@ std::unique_ptr Pal::extractProblem( const QgsRectangle &extent, const previousObstacleCount = obstacleCount; if ( feedback ) - feedback->emit candidateCreationFinished( it.first ); + feedback->emit candidateCreationFinished( it->first ); } candidateProfile.reset(); From 3c23af41a684d5d7a7af0c78248786b72071574d Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Sun, 2 Feb 2025 15:14:39 +0700 Subject: [PATCH 64/81] [vector tiles] Fix handling of zoom levels for mbtiles datasets --- .../qgsmbtilesvectortiledataprovider.cpp | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/core/vectortile/qgsmbtilesvectortiledataprovider.cpp b/src/core/vectortile/qgsmbtilesvectortiledataprovider.cpp index 0dff182ce931e..f037da8876dbb 100644 --- a/src/core/vectortile/qgsmbtilesvectortiledataprovider.cpp +++ b/src/core/vectortile/qgsmbtilesvectortiledataprovider.cpp @@ -59,15 +59,26 @@ QgsMbTilesVectorTileDataProvider::QgsMbTilesVectorTileDataProvider( const QStrin QgsDebugMsgLevel( QStringLiteral( "name: " ) + reader.metadataValue( QStringLiteral( "name" ) ), 2 ); - mMatrixSet = QgsVectorTileMatrixSet::fromWebMercator(); - bool minZoomOk, maxZoomOk; const int minZoom = reader.metadataValue( QStringLiteral( "minzoom" ) ).toInt( &minZoomOk ); const int maxZoom = reader.metadataValue( QStringLiteral( "maxzoom" ) ).toInt( &maxZoomOk ); - if ( minZoomOk ) - mMatrixSet.dropMatricesOutsideZoomRange( minZoom, 99 ); - if ( maxZoomOk ) - mMatrixSet.dropMatricesOutsideZoomRange( 0, maxZoom ); + if ( minZoomOk && maxZoomOk ) + { + mMatrixSet = QgsVectorTileMatrixSet::fromWebMercator( minZoom, maxZoom ); + } + else if ( minZoomOk ) + { + mMatrixSet = QgsVectorTileMatrixSet::fromWebMercator( minZoom, 99 ); + } + else if ( maxZoomOk ) + { + mMatrixSet = QgsVectorTileMatrixSet::fromWebMercator( 0, maxZoom ); + } + else + { + mMatrixSet = QgsVectorTileMatrixSet::fromWebMercator(); + } + QgsDebugMsgLevel( QStringLiteral( "zoom range: %1 - %2" ).arg( mMatrixSet.minimumZoom() ).arg( mMatrixSet.maximumZoom() ), 2 ); QgsRectangle r = reader.extent(); From aa5de9a15a3c2e450e8e349ede5553f08fd81205 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Sun, 2 Feb 2025 15:23:59 +0700 Subject: [PATCH 65/81] Add test coverage --- tests/src/core/testqgsvectortilelayer.cpp | 12 ++++++++++++ tests/testdata/vector_tile/z16.mbtiles | Bin 0 -> 49152 bytes 2 files changed, 12 insertions(+) create mode 100644 tests/testdata/vector_tile/z16.mbtiles diff --git a/tests/src/core/testqgsvectortilelayer.cpp b/tests/src/core/testqgsvectortilelayer.cpp index 4a5f82f0b0dbe..2a55d79f849b7 100644 --- a/tests/src/core/testqgsvectortilelayer.cpp +++ b/tests/src/core/testqgsvectortilelayer.cpp @@ -67,6 +67,7 @@ class TestQgsVectorTileLayer : public QgsTest void testMbtilesProviderMetadata(); void test_relativePathsMbTiles(); void test_absoluteRelativeUriMbTiles(); + void test_mbtilesZoom16(); void test_relativePathsXyz(); void test_absoluteRelativeUriXyz(); @@ -371,6 +372,17 @@ void TestQgsVectorTileLayer::test_absoluteRelativeUriMbTiles() QCOMPARE( vectorTileMetadata->relativeToAbsoluteUri( relativeUri, context ), absoluteUri ); } +void TestQgsVectorTileLayer::test_mbtilesZoom16() +{ + const QString srcMbtiles = QStringLiteral( "type=mbtiles&url=%1/vector_tile/z16.mbtiles" ).arg( TEST_DATA_DIR ); + + std::unique_ptr layer = std::make_unique( srcMbtiles ); + QVERIFY( layer->isValid() ); + QCOMPARE( layer->providerType(), QStringLiteral( "mbtilesvectortiles" ) ); + QCOMPARE( layer->sourceMinZoom(), 16 ); + QCOMPARE( layer->sourceMaxZoom(), 16 ); +} + void TestQgsVectorTileLayer::test_relativePathsXyz() { QgsReadWriteContext contextRel; diff --git a/tests/testdata/vector_tile/z16.mbtiles b/tests/testdata/vector_tile/z16.mbtiles new file mode 100644 index 0000000000000000000000000000000000000000..d113b2853f1c819d8309e68c0965f6747db0e610 GIT binary patch literal 49152 zcmeIbc|6tK`!1dk5h_E3h*Zk3$M@b_(IA>kWyqNJXvjQ8k&q};ib5q+=1M8E3>6up zXp)k-C~2TU`Q7i0p6BEFJm>d1|DE$aTWDMRT5H|wTKBr&YhBCBZM;j*!HX%+a`kYg zddcJGES$r|HD{x|{G2&+1mJ4{e9e6D!wa67AK-tkzrFsqmjZLtTuOxCUH%0p=ZM@E zaTDPZP8QY_>R!+Z1)L8K0~`i83~(6WFu-Ae!vKc?4g(wp{-0)GC;z-9N=jT-UR0VB z)6?Av4kxyrUQ{pa-(N4#-mSCAL`U9a(`G##`M4d)V*H0?! zchMTQbXO;DXBYJCzy0{P_dQ$>{CN{ztH?VzQ|*|ZYHT!v>P7wYF8c@F-G=&T$ZP&(0Q^LCVazo9myOeyzX~ko@hy>);tJw(aA7cgr_8W*U`)N> zo2J6lVEZmp9r^7BTXf8)+XT#C7Rayut3j2iAv-XXZF%{YNI}z5?Ae-Xaq9cL|Cphv zvcI<>@8IIav}1Zqx5egw=HyEI)3&@9)7MLx$^*8Gas|n>B|xT$ zj=71l_S|_(#AUhY>~XkIote%|FDg2G?*BF*6d>>FB0mF?UyYV1Z|9n~L{^r|Zp!58 z24*mG|I_&Ccc*HySyhqup*ndprx-@h<|6aO=ZFl8w2IslDG0YiLwoX(( zriZ73hSebj2Zn-%0?pgOiQ(X4N5JC{1r-Gb)06Ju;O6Dv>H=>H>!shz!f&Tx;inbE&#J< zI@sBJ{T;_P$=J&S41)KaTcff)1_YMOBY*ZB3Me6bDcoKyd)Y0Tc&N z96;eMJV5aP#RC+N{tQq&K=A;@0~8NXJV2qC08j!z2>>Mklz^52lmJiyKnVaP02GRd z03`yH2v8zGi2x;{#;LIfrRuFi|i6GovtB0RCT0DMk&0!xJzBm`xH1M<5Y^V~iS>f)FSO4k2PN6bu0v zz^LIcL?VVrK@fyQAmR}q4x>f@01ksE5Q#WEg@^}Ip^QYtktiet=q2MZ1Txwj5l6uh zV9M|a1qZ{!LlJ@}BRC=f7$xEH2=I+jqhP=%07^lK6g&x?Jv9swA%m0PNdyvwKtf$Z z4cJ0R;BPoG0guO{UZRF0P>2|qRtg@2A)-vGp&fzUPz%0rsE?@O$ykW20>;8T#2{`j z2RAn+o$BJsv}G{q4xSKMJP#?*sGiK}P(p;Lawl%iPTsj@O>H z&fZSYhLZzC77c8Gu@KMlpe3GODBRA0>1lNcrsaR@69R*aA2iNh#<1A10X9MW3wYFn zJnfh+OlTLPq$@iDg3K~wyS(adc`Txir2uE@I0AyB$gfgWMMt5E4nq@5TqUonijG5- z!F2Hig+`U?sp`UHGMEf`Rag0gSVYa4#tupHGm%CWjk#(NTF?Luwc+-f&RizQEr*!3-L_F9{k_iYbG_)Tg31Khf1-#tSi>99n~+RNSs@p>yHvKBZ({!;+FfXR1nk%t|>J_0Bs+YBIe6;>u~+A zGzfmQ(v%#*hrXOr4CV=POLI+21HA0lQ^Eib`g&Rx;1=Olr0fWrWX0S*Hk1~?3G7~n9#VSvK`hXD=)90oWH{9nqzGA>@Ox!m}LJLz*S z)*~b$nL>fzWI>4V>q|Hsk%UF>|G7lI%z;nN2ZsR;0~`i83~(6WFu-Ae!vKc?4g(wp zI1F$Y;4tt%hyg)V5|}?F39#?~=Y5(3pPUa40~`i83~(6WFz`Q^f!08-d0au4%B17JR;9?Gnuwicd2hBhPtGISJIIFM05xakyE}e!hMZL3y!d!R{~1=PJ*0yg3D1$Y123z5 zhgAuQ0`on~Fh4Aw4&G4oi@wb~dqq;}=d;*{B~g(Lnl9a|FS*18REN8djf$?4TR`3r%E0wCM_&oOsa{Rek*yrI(bWL(cl{T5SHR z?zq0kd6$fPmRrJ_-i;3U_KmvveCzJsQkt(UJmQ}3vW&-vd{y5)_tap4+xh!V2bb36 zx(}CCp2+R`^vsF1A=>!#bEh{~CGvSn&i#5i>M?vO@ib4&U7F|wbId~~_w;9T=iJJ~ zU)~3H992xByi(g{aK^bT`Yb(`ymsi;wo?tSoA*XHFbn(|k!EF&-(#a5FNH-O`mMmE z=ESZ~3aIolsJj1o@v5S8-Op4dN;@2UEX=cFg)SWJi8YrVxw-BoA~N*QeNi-HQIkuK z{4>h6MYUJ!?&eG6+vn#6ci1jF`*ev~o#Ppv*6xCz*Lyy_Fv?qJE~s8?9{YKKe9N1M zG_cs&#ZNUb`tjPB``n3Do@s6N>iX*E+TSdakMzy&a+Q;-8K0kNv zw|hSgfbHAwd}{xHvCa&u$QM`W^GrA*=>;#TyS`Puvzy`6Q#5xMpJ zf{dN#HlHW&9=49%ELqOw?9!@c@oU&AB-ex@5q*23lIVHXcb_B7)0u!^Np@&T({i6`$I zPxQF?I!QchWSyRP-{@{>bGu}dLQbe>_=j||+41~!z8U%+9nx?6`ih(k&e_v#(jLDQ z<6Ci~DAmqQxG>PkZEwXo>ooqRI>m2K?apO>ujYNjOT623!z?gSNfnXt$(Nqnq-fcg zyP;M(Orp8pBO+KQ@7vGnYu~HsU&)mG$_RtA6&KzoH3qjg@5trXdHmt}*|Un{o07dP zD97WIy2(oX+N<+fXS?L+KKknRdS+qI=f>~-I3C)0)>gu(qbAtO8JzNnN?C(IQ{9Gs z*`y0pl_0Trm9o3x(T|}32W-Q3Fy1aq}_85?(Fw4p9px@GVCO3Q7Ya2+$A6B z_N9mL*}WJR&P3RL7tFX}e%`2lg1+qh@Ym3tZWP|I_|GwZRnl~1FmrK{Sdq1{4429S z0gTnhvK-}TMnT>(Ol$}9268`W&Ahj2#hpl2UHN%TT;=M1_h985o%51m^xA&#@^J zS}|9Uct7^MPefEcCDnyIL9x7=|8cJCfR4nyQ%T($gG(&VHdQ?zj$%AARCNR?H8+E9~(4!Lg;aipO)?S#*oSz+{26!T7{{s}&Cp zMqG`pAPDnu7d=>~8QfmM5=c7}A`#Znv+rt}(7c>j`TNYEdv9Jw^|q4LL`>usy^tAj>J@a}+h?77U+7YF z$mfe9ysoanE&EjKo$Mr%x{FlYRvz(8iuigxCwRrdufg#zg%h?<45i9DcwV=lQ8$0_ zHE*pr_LFSn$17RqE7CxEv9rh5$t9<~r{5Qx=;5h;L9-)^1hONVSf8(Z?~OLi`(##E zT`U{*F6OKvrT2-DS#Q&CpD~Z&w2tMQk4x-Zx&H+BR};7JlTBtfV%NWzSkTv|a?{|P z_)*6b+*h`Wsm>)BPFgh7#_rQ{@1Sr+J4B5=qG{jUtU9;rM*d;X;Cw5y3F2-mMKG)=FN&XfBU`bJ5ohGcy#l~=!SLtufEqhxvyIh zVcabfLsYh}y{H8?d58bX>gj zUMc1ihIvjW|MA<0qy6jlpIMJd-1wS$uG?I8?k(}+5X!mUBZ;!>w+UxRZ77#PR1xzq zp^_63AyTofC+H!MDKZbcUUo~sig9`%NKQFd9rUVIZ0k|Eu2uXNTNVAvM!B_*R(6oL zPgH26yAh;II+x|ws=BLHIgbt4duuO4RxF#h<=YFfT9-vitL%bCTl!qJ&pkQ76XSn! z&d#0Dx?`hbD@jM!#PLf0o(ORKe20FN5mxm?rNky`xaWeBlbYlqS&ZlQsNvkEIXs2kvy;aRz%G+E|x4Y)FcP#x{Yok;DKJ&->;7?aoQZ9K!oN^r( z@qboxIYNY=zopah^_6X*vF)Be7bT1j4-kSL|IVGi(ycQ@Xz78iEKw1J8$&JsZwf_B7Z!8Ftyl z96T9Ce>9@C>~b|3c0T-5_x}TPL8$5f15gPX(<-qZi z%B`cXNvn*8zw)#yTp4KQTO9QHr~j$k>fx5mRmnzFm$pG3+J%Wnnp+PoD!S~cvFmZ8 z{~=sNWmnkN@UnjXlDG%^By2St74lyHwzCu^`@Jf%p8GWBl_3LTTk`qP*178H!q}V^ z+)z_tgz4&~9k#>U_xaTahM(;22({SaH|pLx#Iu7mwsP^1*wV(3@T?A=73WvPh~F;S zx?y|Q5T8$hyjyGczV6htzQ7fBqDAk29NKa-jqiQW!OXnJ<(~sj+LkVue7_uPyNCYc zE{o@|X1&4%M6~lEw9$KI%CVg$-@1d(;a{#fFSAVZ^2y3qo-T_o-4Xlt z-ul#n>%-r3PpOzmd~w?_%6fiNN^VhW10rm-a9dZ^xWQt(_|D=q*Q{!(#36-JQF6-r zhVN@sY=7RP(lY%553dl*a{DcK=-Q&8#_Oe&uy3^AuC=!EYSxR-{g$}Vds8TO)4ke; zTJQDx5>|IstFEvNU8}kL(y{Eko8GL=i-Tkj3Ku=y8`|7?@YIcX`qtrNM{84p5yse^P{x*@?s|~G0PUSP%G{`#}&61v}>&klJp+BspJ}a zzhJLlyuwn~Ux)4IW514NP3~P0RJ5PJeC5s%ky`N?Kj^Um2Vj~l0^>hTQ~Ra;~`AY znIXGvaVFy`4PEnPKD!6*{+S&kX1(H0rqAt|0LSLwg)R?$MQ&wObUq1Dwp7I!V#Tl(pU z`KRhf+`qO&0kwCi(v z@xh04#9uu(8<$x0sri0S>e4cC-^ktxo2Lc*3ccmFX1!x8KVG+ae4IX6Hu`?|&C$C( ziMoqLM6NeU?n$ezxPDDaSML*fZAQf!gWk@=wv6o5^Nao8?LIK~u98@`hw<*@5-qcK zvJ$;+aGm4uWiRu%iNb8F9kriVT{~^7DX8n2O;(<~dU$P=O2M~RBQXzX(zR-eO`3i0 zFFZd`N6#2yS@KVm>p$3e)a`Zoc~h#-ukga(IcpfnLy6VdLrI4H?FGB3i^k~-OTt|Oew|-B~KB?1FC?l2SV*RE1ZMS-xEZxbKp z95=R19_>&uJ@!b)vpaCr%aMYKZ)z5A-qa&onjQtdW1TnBroW8b-Z#+Jxp%=K6Pnr6 z3+q#^pUjx&E2X3=ow3Fw{pZ*9qwW?DE(SK4MwnaNt8zEYDviJ5@$i6# zngbQ2OB+K)?*yLASgHN|vZwR*OKaAiTR*N;9q>4Bv&p3rr{-0~<;NKfF-^<#80M#~ zEw_tV;@w7+i5Kdh2$?@u)DE@!{r;)(ZP(|ud)A#uaG(D~hN>(?9gkrM+Y3!lAfQn{RT`KImfcOmZt;<HrJ%{I8_JbZYx!`Y!*nrEycZj3i5q#$?y)*{0UnFy1|Sudnazes=g-dy2+ zb^iIDGMZAijI@?}jOE^({eua=9o8Rgp#Ndoq);lt)o0zO@S9uqI19Ay;kdF6o36dO!jfp13BZ7*5qsX0=2y& zk){FG8?OEMxvib+>*E8$otp|)zb?NOK2fsLU3~k^AD`1l*0$At;8F2V-IL#E@U6)t zzOpW`RZZ@T@A9)lA*um+@gfr6SPKdKz)bZg1)SNHi!f9_M4^Lo&tILVYal=@yueHiyhP!p?_ z&==yT_3RO!puf?_O|62Y17E9>wFX58JhGPTCH;i%%0w&!@~(>bj8-jHFT1YSv35_T zZCN`Xubfyw-UShfpZm6|53g$#CKUPz;r24%+RbA71_Ed0BY57N|G!fR%eaRvczHij&5qc&9LQ9TC1g+&!)3lCt zlj=HgZ0)>jEVuhr;v#$IS|4{)s)}E*N3h7_O?^m2NRFa)z?-GKPwk76!}cp!pYA%? zx+O#9N*A3H9Ak>JRJ^2*J7}dl^1wbLGP+K#wl7BTQ?1>nTAlAbp5J>AX4<_uMJKCd zwo0eXy>oBSJ1M*N%XNZFjrFE<-%j4_x#Gf^TQuuiw=KV99FZwNSlvZPfFbQ zF6!&OX7!kpNGPw>xv-3Pii?k(6Ro{P99*aKm@ z&v0b|eQde$vS%q~33E@`>ReAqNT>|&3J*WYFC)5d--40{AM-v|Dz$0njp@>y?^9NZ z?U$<|M}Ox@toGvLUVAdt_tC&0Z~5{)iq5;X@nH=ZPmI&;ZS;+JY4pz>h6`dEj=zt6 z%vD5LI=)D!NVi`CC*_r|y~gN6%8twUTj5Kc9LD9!gPv}F8@G7J5d2+x(+6>vJI)vd zX^5GmMStCPz2R+}s(Q}d4&PO`=PT&BK4?iknCaveQB&0@TrZZ|k-)cj16JtQ(R2lU zR?5{~j8`%4^7$Lj__^OP6yCr4>12o=xLc78Iel(jytaW?g=Mv~=P#%Wfhr+}Y$bwcrR`M3jC8_hJ#ms}>@dc4`M zwAvzibn`v`NWH`ojqDR|3&mX1S-YMN3K;#?f44?e>55L6PHkW3M(IJO{gGEjDVmd) zXfgVd54Y+OarfVS;5jTFS9#sk$I_MILbp1zoQf9rY-5!=C0g1D;r3oJ z*myZmCva=P0)bmk#1c}A?1gHujehlU*AB_dQ?uM@nx^slpX!Ejn!BvG z;My05NH0g;B7KOc6Tz3i)^W1&ZXUVUb+e+x7=8;Q+EOL%3{RQ z;HvK9tcWjmdc2yWGVgxR6NqS+KIZVEB9)&k+QS>3Xqc!m^ltOeX5q9?Cwue`f9g^+ z(c8f|=;pIg?R3_|s2!1pjoTV=k$3c)wrGAiK6zAiev${Ttj@#6Fx3x6cCj)#+*VmM z(!M|_bZl)3{2{J8l4>umpnhgr?E|>r#H<#`iZoz^22tjNox34 z>8P`c{etyvTlYx#7d+Q*!xvikWZ65Ovo1MxCuqlubUwLzd|73p4^Eeb->EOt(70Y< zF_G+dx_KGq!kyq@o!I$dErS!woM>nF92zJ;Wf_tFNcJLCwB48RK=-f}_GJZO@6iPH zzOK$4?MEf|4?fMhxcrt{>*K1gX8IQ@PU`)h(^I(6^HgwL$2K`c>_hrUN?w1J`|GsO zFLTRy*9@v=ueNc0@FcCPXepLI4D&QrdB+|*-|)zxU3DfO8#D-8=!b(_iAiW%>Hcay+69PX|fAnKj08?Zxtu8ncf(nUrQtyVXwZj#)x z>ehRt50TmuWYb;Gif5B<&E26_$s36%KU!8zrVIu&p1&f0!LBfTA9voC+hyBAyNuf2 zExzI-dtX>u{Q6-7x@>+ZPRcuQ>r4}d zICJ}vq%p4BqIIf2?ryw#tTK3Ht>78z#5|hT<&tvfnI->j2988Rk3J(c| zzThUsWu7}Ry8fP%_R7;PpGH}~B)YG*jkmnSm*{T2oO-%VtM^Q|$BT^SkR7R{Tdm2z zEF7$)7w$cl(BQF)BK~dXjtcyywWBK5;$9l|@z%P}?kNuL%zk|O>amZ8UJb3%xcH0> z_XlN}1LczHx{V_qzg{mbAv}GCKhV3VO>w8|gQuH+t-GHzvd=m?p`vfIO;EO|=cX%p zl`Z{VAJ^Pk%vhRzW75p5{OIVp@b6-Y8gCsl8~p5yo(}gr^fl_Qx%RZ-Yo`3~6(t65 zJCwwA?lYM~!K&`_t0?5KW`T$HPZX4M(lD@5TB5zH;JM!-PJ0XIg3uW+Xz$_ppwS=?2;?3Vv9SKOf#-D zV+xw6s9*6`ZA){P zS(;eAn1`0{GW-&`1xY(DZqa+T)c!EOHRaCkhTy?lEx|`}!v_we8YcFi$0`?F9JCK< z^xwMc!?GyNMh6OhL}|pnz5I~NXxzOA(Z;8~T)jxtjeHiQYyS1v*b7D5wPw~4HzK}^ zC*JhlYS~thbaR=e&3Yx(l3!a+r~bOkN?kZ1`r^!;i0-=`>rcx(e|v?e{E76Yule=K z;*vWX{dlPUt5VMsU6>z?H*6B>xHqxst@oZ**9Xt&^CF$4cRhTYx#{`g+~MDpn#YSg zcOjq7N4|gNd)C76;bq6SR*my4n+h_IcuFoi`~J4@n-%?{FXGZWlFWjBXj&XcjELs; zV~xTI%P!cgHHv8YG9bHQ*LQKDb>9g0pSaT3hf-GT^h3P;wv7+j%kNMTe5pIhPjuD@ zn6EUt_G5>M!Gzi6D1jZ8jk_-U%k?;fQwU%Jmw%5PX~{`SOm&z{ODH~8e(5u zH))Th3Yv@(zU=Q3w~ScnJC>YQ!-_nFKh$Thk$h+EwafeaO|p|;oj9hoamk?gm$R7z zbK^SKkJsh09?N42E~UP(p5GoAt1uufIZlgi=yTMqxn11hk@Vry`p!pv#&A9mp(omvnkTWLJ0TW`TqA+*bjHlpK>l;|Lf9<9w|psB&Fjm zz3otDRnkBlu_DEtj}=?ie>-=FV(xcUOT&i!2mKC-ZQAefGL#Z|q>xhDY(E@#c>b}l zW~qbRIlQkn-B+-}91gY6Ph9M^#M4FBi_Be{zSbUTQc`-p_x(#P)#n4i0lxgo0x~V5p;r$`WFnmQr(D$O}7dFzxZ*vP}T}pp! zn=()7ot4hXKzlu`x5x1p{Mx>6c*)&g9hOLq5t9rjLn|(6l$k4JL=~nCU#h!Ii2be` zeJkeKP5ChuZ=?Crhlbv^S!FUrcSN^IYdHLr*%etnhkkE(Q~H^bE1}{KZY)Z2_xWsR zkow#_nRQW^+_-UEmL_Er>T^s@@a0bDYN6&Od86YeZav1PCn|c#n0$WsUE#LPNP*lX zCO@CUBEjAbZFEevXo9!cmSOkLE+KT1hlOm@X4~>(NnsW{67t4Rmb-a*3>H0Jy(8no zGHUnl?S5mzQ5R{BtI3+pE`H=kH%?kcZ?=?DtWMG&&J$j$eJ)PUNU2;@w~*NKd~e3J z7Q=I2kNvj%bofdxR=P(j{5x;ri@{|B$s%itciLMbQtqzgr zz2*yK?S1-dDURi}$QZY7$lHBHfj+tdTYQ(NJoRdNyFRl$Uoyt7V3(WxiwB)C9}bH? ztq#gu7AGq|UU;cxSA8pYoK(KV)wF|sLqdv#`^ehEMLT=k8x0umveyf!Zd*O?l3qH_{2ibF&ZWPP(X&Z1Z8G@r8?GOFT%U%P7+t+Erxd@Tj(ap}B4;IC z+~a(RaGpq%eWi64rjWk=eDQKTX^FKV{z=NH?dE|yN0XmQAGDV$GR-n3IZP1p6LF&@ z*%R%>`MWBHZwH-w+kd>O&g-DbwU^nV3;ejY|2Pw%d(Yo6AbilyvPNx7eu}ExMxo}h zuP1J-#Y!XuGMLTjngr?nS$79*O|%0y$vTqrAMV*=9g`RTTz=2D{H%fRn-kAf8eHj5 zv$9v$v@Dr#x@zT?kwf$^S8m>oA*eB4owaR$Y4~l;hH)e^J3n*CYwe}7hie?g9Tz^y zh!1#Yzy1tmdDvHPV~d01QeLVhN9zak_U)X1c13Na-C(Fg+rSsSHho!Uyq&9Z&G&OP zR~iT6lnoBxKl`w*`6op;X$I8f%y zD6FcY&9~fEZZaYKVkgrp@exzV((spo`jKe2Q!ls`cD^XsDjplN&xx*Pgb{g~F}!AQ zT(U_Q)Tc~8^A9)fz79I7a&S2@+kW%G$X7;}=YKqdY>nK9>`IsE)b@1#@$LP>E7kei zojTg8taim_rSv*GatC(}$M0t}hHMtpNOw4Qv379jDbsI>HR_m=*1YeB3szpa`zfX4 zi$jUpN9PG))0g^5wqYQCPiD)@tGF{aiTdh?TeWO*34W#dqsHUbhyB8tW$} zy{-3*S&{HzSH{Vg{DBz;X&YB>IvaZ?dvZ*HQ`w^^!xO3(jB{>qgd zy31bee8z8e*TOYtUWJYZCfL+Ji}QHRC==l#i3-DCH8x5mJ-dC|Ztcr3f*Ms=-uOW0 z`$*&B1F?704H2p8-Q7($-ekSsy?}b-u5)VBxiD|P=aLeMgaR8A50A^e#|4hOkbE|A zTx!tsphmm*O57vu!jzUwVRcExrET|I<5pB`?x|{I^{H+#@V?_NymzO5n6it+QT>o$ zH@!szHj!bN@xEX;jI+1Fn;nj-ry`zgt6QJqx~b~1&wg&^b^CyoG2b`s4Y=f6SXm^v zXOn@`C7-Or?wUp6r2KVytowr|N{aQ&oBHdm2M+UO1ntqPs?D6Y^R?;lokef- zSW)Z4E;<|EU)rbmMa%0%w$WbAB;p5Iok&~z^Ht|f*I1O|t(VJmKiksK!ab;Pl20jb z`;U1eckI?=f4E0Jm#8L~UusXfxGwHOMEz=V%z^@$Ef<3@Zkf@L zPY2@@E>>ODi0r#oMuPc?CA%%+?bSr*JZ^FN!mn8_oRxnWXQyID@RRMa2v1yfaYSRp z(e#;8>4FtMxR%f1RPy%9TP&R0LHmWh`wT{~fN$T+KLp|#Z}zJxUo zp6lHBsdM`hy%8VNTj>9FbpQS8(l>iTKBRewEgRp%I3hE@^JaAAcC#Fxg^nZ2KXPk| zggj3jb1c;ILhL??Ez=oK-QcqMP^-p{$IIf(b5^^D)F>G11dUxk=VM-Kc&R`2*+j?# z(ZsfuIu{>Rv@4NibC$m_JM^*aQ;z?Uvf2l;`s9skpO)BhpR}@{ z6wlo6Q#wDjsfg$5{tyr8xY|P6`Zzyrzk#zB_kGAZrm0mOElct`j8zq_Zn>lyY8`ng zbn2FY`w%wral-3f^U2eiYsL49+zGiziNCn;*chARhS0EoATK9bO;mdTK@b8$%-TU*zuq$ntb*Utt z5s8|Fyd#v%1IcGPQfklbXfctuZgkpuvSY~!m&?6lbs{HiZAA92TxZ91rEfmr?eh~x zrjix)DjCZS4V0EG*e#qE(dB==Oeg+U{PneMF<1kp)~T@LNn=)5PEC;gc5CYC7ajRT zi%GK^uC6p)9qKaf@9WQG_Hqq|6sT=cF}-%>es#jV_Uo`n+W7h{QXPgbjt>u?jBDA&XJqdmVp+7)?~``qMLUhX zoEIOT|8?09=?dwm=DiDTG=8wUB4uRag=*hb?K>-VrSzLSl^YHGx{6xHE{zrUyfEEN z+SDdZ?s_}9u00?lJWr^{F45RSs`%olzV4gdZIco&bk#Qp+>g~g*v7Ydb-|_^nkh~n zS4Ht*@_RF1CHt+ZAG}#-^F*1@Ri5*}|9DMEf_m?>vU9(l?fVk$TIt?e%e`o9f7#hY z#ZL!2J~b#tT`BX=jk7hhxcyaF`Db%=kvKji_>@Vz%avyV>YpA=(tk)LeS9I}mP?Re z5E@1Vq-3m7x!ry zsrq%;4=4WOZ(rlRVvlHs^&8duMSS^Iej#Tn8hFaT%G^8JqCgZFT3W`NZJK*{ZqMBQ zlP@nzNT|g}daNDRm-I zQpR59lh-)I!?p?{11qm4`R|AwS2~?=y?2s3SLK>Bl^?S;%u#$mL04`~x9Ytj;^&eH zgVOa*=h_EPaCa2ZiIzf*aspQuzfoXS=vm2)nkL`KaHv#nyA)b-Y42ejE&cBoW0b-v z@)g>zq}|Dn6KM9WD~UTMH#~H`5mvi(&Yb^#|1U@)LP}J~s|oou(PW`&cnV~wBtX(o zNL2|bGub613S=-v2#`h-gJv#OBVfpoB$I+cDDWR-Vkrbj>IvCgAzdeeW@A-@ zjGknKfJ0MrA{chQP9lOK5g=(N1(M4GNoeat5(z^h!+7ur4va+&MbN*QNWznFBq&A` zwyGfnNYn^fJ~2cL%bekAp0s6f!gcNmJDjG%F+t#)=`5$#{0^PlOC~67j$u z8HR=Cp;bdD1Tr3nC*dKBB;=JvM?=Dp@e~RqE`@J+gv~L$O~66hkjfNCg6b#={-z`3 z4aGouQ5>2Q6)l1u31kc~2jhW>MTRR zvOyGZYaBQRj2p59L*tNb7VwY)7?uEZgXZ-`i-2?txC@?uLzC>HB{&3Z2UcJ>XgXZ9 z2t1nvZifCtv-hG!klvL{g2@1HK=c2iMPzVe5&&^T3Ys~XT?B7KMp|$+mVs>87BB2w7&q zS>|`oaDM_B0>Ly2vfn}@KqvHyE<^9PQLtQz5b_{{@N|bHblrmQ0EKAw zWV9(*d=OV)DM3!<>3Srv0T2Fwy4w`Z?D#=|)dI0#x*i!p@Q|Gu^$#@lG};st!RTPA zlOcYxi|`omAqWI8ATp#dMp1b17a$Xs4g`uR*8)P>@e~#&J1CB1YU?BT9Bv}R* zoShDuNQPXz;EY5tiiDe;8Tzku=YO(8m~uxk?7H3{sR1a?gVyC!NMkzI$#u0v$kA+qZb*>#BQIz)CI;#3`WZwR{< z!p0+PB*MlZYz&Fr8i`$(#Kx1^crv@3%&tXd*CMlPk=eD#Y$WB+TKUTt6(F&bf(GOV zpY7fbjDJa>4tb~?T@3L4 zps@%8hcK~t3JpW~7YGZ-BoJ^kgh|FQXF+Jww&3Xubh$EFG}`Pz&p;@6CXq>_BM5~t zyA}F$D|9T4fn$+LEZXcj!p%Tf6g-v4f}IKtGkef86F?_0@dO&o0Bm4pnL7hv5@@gs zComuc&9a4nnYINU9xNP%#bjXcv*w6^pN7DLkAP*u=9|Ts3;Quj=gc+}+Qt?zK9Dpd`Fta+EaVZS=ITHuF91Qi}Ab1vzOl43J zgn`VqWu_G(3wAQF2>_RvA z3Py+}GRU({o`Jxwg+!;p1{hBJvqm)oL8Ci?g~QUIp;?fb<%ZB{6gZ927%;Yffxun{ zp)z294oBQskeL<9z|&zX$D~u4%zuNh2y`++CD7>%)~x3Mab~$;!Mm9>@Nyt)R!1`s z9Fsw1k|83}XtNz+20|n=DO6Ompb=+=BW$Y3)5v9A9>5QtJZ@EI!cA0wLS z2tqG|i5?mtGX9IXBqkOMt-#})ID3v}S|NiBLWSr|p;KnN)eMBfB+}p+OJ&lK*>f}l zp;D*_JhC9{QD!}p{)`BCBT>k7giOcI3Wlt|b?2cx_Gpe1y5tIxX&TMmMAaptjhy^VGHZlL%5i%24;l#?qg22LnrT;Gw z3Xz6k(BVN0y2C8UOkjnRDVfB;GEm*-UmzqBl|p6`VTZz){Bb zP%@lc=~OQVR~M*EclCDhQqaKu(M0~sY0uk*!St~603_p|Z85ss}y6_Oh9&%sq?`n(G7%s#LlaA0`Z z|7{2$l>HgSf9n>+B~>`+0m06_%Z(t<{VV6m_s zKnVlM0_0>6OG)TH0l^a3LJorJ=p2oQtNBDj+Q-5R|v0GS#s!GeLH?xPAQLIF7vicoo%0&xYDTo5x+8BYz? z5*Y`p5>z|5`2q1o4Q^D3aJz#cz=i;XP!xp9pKL9g1Y<&_KDh7!1p#CuxOM;%*cS*O z_`+2Jh-6R)6nfN7xYI#zilBWGg24F&Eus)m$rY|{P?3{;H9*9HAP*WM5!LTeT~v(- zcQ$bC0RlCgYCxw%i(o22c1QO(sDO%=fUJtjUhsS-v*k130@bx)9RV+}E&+p}`+k@{ zEV_3D>(C;&KS1wQAk>2mY!09nNaiqO5dEPpXi91%xBvsDU|~XkY&uCGoPwPov7#eD zIe@z})C81o(Bx5#SB*qQ?`QB327wu~RLzRBu1(lg0-~kHU z67+A>9#Du;4}~JI4+a903{D76j~2n4qeP-4g2aFt0gS^);HCm3N0<|oD%7n&+JS}< zFaeb-Q9pqJ0Y4yFPhFS6W*giNSV8aNpdS>4E;TrLL&tE_fSN!7DHG-!2j&wI(BaV{ zD5Jo=0oV>4!T@2d!rcd`x^NQ!HK)~Ya33ssa|92KDWMTw0^K0x!-XT8b#^@jbv4kr z|ET7$cHxErSO({x)}leX0<{<}M?g_VFT&UrVQg?M2}Tfr7qkQmjl;5mQG-j&6oJkO zf;bu)P`wgGp_dXM@W5T#3a|)M9 z=;i2i2{;}ad*IR$oh){D2zU(~SkQ~mnR?(M5Dh5PB@jm8ssN3VnCUTt z{z1gR9Ujah>S*i^;rI&64eosZY6>on;7$)rgFB2V6oeuO?$8@tX-=1*H$QMW2Dd`f zmrHQ(0l^vK2ds^m`#N|5z5!7I?&qfK!Rm$!5-A4;nEg;z@b*b%)=EJ zEP9APGZo?a0Oc?hf7t*uz@Smjo|4m1FDJmlft3SROg9A)5AKnGcDS6HE`nMx)$rJW zKsQx{-cG_gfw@J{;Dp+M#yz-8g5^C;0-TC55M+QG@a}00v Date: Sun, 2 Feb 2025 15:48:24 +0700 Subject: [PATCH 66/81] [annotations][ui] Fix fixed-size unit combo box not set when editing a rectangle text annotation --- src/gui/annotations/qgsannotationitemwidget_impl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/annotations/qgsannotationitemwidget_impl.cpp b/src/gui/annotations/qgsannotationitemwidget_impl.cpp index 82a90e55167d5..0c73c750f309b 100644 --- a/src/gui/annotations/qgsannotationitemwidget_impl.cpp +++ b/src/gui/annotations/qgsannotationitemwidget_impl.cpp @@ -594,7 +594,6 @@ QgsAnnotationRectangleTextItemWidget::QgsAnnotationRectangleTextItemWidget( QWid mSizeUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << Qgis::RenderUnit::Pixels << Qgis::RenderUnit::Millimeters << Qgis::RenderUnit::Points << Qgis::RenderUnit::Inches << Qgis::RenderUnit::Percentage ); - mBackgroundSymbolButton->setSymbolType( Qgis::SymbolType::Fill ); mBackgroundSymbolButton->setDialogTitle( tr( "Background" ) ); mBackgroundSymbolButton->registerExpressionContextGenerator( this ); @@ -753,6 +752,7 @@ bool QgsAnnotationRectangleTextItemWidget::setNewItem( QgsAnnotationItem *item ) mWidthSpinBox->setValue( textItem->fixedSize().width() ); mHeightSpinBox->setValue( textItem->fixedSize().height() ); + mSizeUnitWidget->setUnit( textItem->fixedSizeUnit() ); mSizeModeCombo->setCurrentIndex( mSizeModeCombo->findData( QVariant::fromValue( textItem->placementMode() ) ) ); mBlockChangedSignal = false; From 8dc43d7eb683458f8fbeceee5f86ded62fe65a97 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 12:13:10 +1000 Subject: [PATCH 67/81] [sensorthings] Offer choices of non-polygon geometry types for multidatastreams Fixes #59719 --- src/core/providers/sensorthings/qgssensorthingsutils.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/providers/sensorthings/qgssensorthingsutils.cpp b/src/core/providers/sensorthings/qgssensorthingsutils.cpp index fa92c1a2041dc..21358ba76c9ed 100644 --- a/src/core/providers/sensorthings/qgssensorthingsutils.cpp +++ b/src/core/providers/sensorthings/qgssensorthingsutils.cpp @@ -661,10 +661,8 @@ Qgis::GeometryType QgsSensorThingsUtils::geometryTypeForEntity( Qgis::SensorThin case Qgis::SensorThingsEntity::Location: case Qgis::SensorThingsEntity::FeatureOfInterest: - return Qgis::GeometryType::Unknown; - case Qgis::SensorThingsEntity::MultiDatastream: - return Qgis::GeometryType::Polygon; + return Qgis::GeometryType::Unknown; } BUILTIN_UNREACHABLE } From 2cc2a2224834d4fa8a76b525486f18de635c381f Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 31 Jan 2025 12:06:10 +1000 Subject: [PATCH 68/81] [sensorthings] Don't allow expansion back to base entity type Avoids circular expansion Fixes #59722 --- src/gui/providers/sensorthings/qgssensorthingssourcewidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/providers/sensorthings/qgssensorthingssourcewidget.cpp b/src/gui/providers/sensorthings/qgssensorthingssourcewidget.cpp index 0438dde67ebfb..0b818da61e2e1 100644 --- a/src/gui/providers/sensorthings/qgssensorthingssourcewidget.cpp +++ b/src/gui/providers/sensorthings/qgssensorthingssourcewidget.cpp @@ -774,6 +774,7 @@ QWidget *QgsSensorThingsExpansionsDelegate::createEditor( QWidget *parent, const : index.model()->data( index.model()->index( index.row() - 1, 0 ), Qt::EditRole ).value(); QList compatibleEntities = QgsSensorThingsUtils::expandableTargets( entityType ); + compatibleEntities.removeAll( mBaseEntityType ); // remove all entities which are already part of the expansion in previous rows -- we don't support "circular" expansion for ( int row = index.row() - 1; row >= 0; row-- ) { From 47a72b405654f984681c3957738af0c678d3d2a6 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 30 Jan 2025 16:33:57 +0100 Subject: [PATCH 69/81] Limit number of hardcoded strings for layer type by leveraging QgsMapLayerFactory::typeToString() --- .../core/auto_additions/qgsmimedatautils.py | 2 +- .../core/auto_additions/qgsmimedatautils.py | 2 +- src/app/qgisapp.cpp | 17 ++++++++------- src/core/browser/qgslayeritem.cpp | 18 ++-------------- .../providers/qgsprovidersublayerdetails.cpp | 17 +-------------- src/core/qgsmimedatautils.cpp | 21 ++----------------- src/core/qgsmimedatautils.h | 6 ++++++ .../qgsprocessingmultipleselectiondialog.cpp | 11 +++++----- 8 files changed, 29 insertions(+), 65 deletions(-) diff --git a/python/PyQt6/core/auto_additions/qgsmimedatautils.py b/python/PyQt6/core/auto_additions/qgsmimedatautils.py index 551f882dfd1b3..2bc2b665a9ffc 100644 --- a/python/PyQt6/core/auto_additions/qgsmimedatautils.py +++ b/python/PyQt6/core/auto_additions/qgsmimedatautils.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/qgsmimedatautils.h try: - QgsMimeDataUtils.Uri.__attribute_docs__ = {'layerType': 'Type of URI.\n\nRecognized types include\n\n- "vector": vector layers\n- "raster": raster layers\n- "mesh": mesh layers\n- "pointcloud": point cloud layers\n- "vector-tile": vector tile layers\n- "tiled-scene": tiled scene layers\n- "plugin": plugin layers\n- "custom": custom types\n- "project": QGS/QGZ project file\n- "directory": directory path\n\nMime data from plugins may use additional custom layer types.', 'providerKey': 'For "vector" / "raster" type: provider id.\nFor "plugin" type: plugin layer type name.\nFor "custom" type: key of its :py:class:`QgsCustomDropHandler`\nFor "project" and "directory" types: unused', 'name': 'Human readable name to be used e.g. in layer tree', 'uri': 'Identifier of the data source recognized by its providerKey', 'layerId': 'Layer ID, if uri is associated with a layer from a :py:class:`QgsProject`.\n\n.. versionadded:: 3.8', 'pId': 'Unique ID associated with application instance. Can be used to identify\nif mime data was created inside the current application instance or not.\n\n.. versionadded:: 3.8', 'wkbType': 'WKB type, if associated with a vector layer, or :py:class:`QgsWkbTypes`.Unknown if not\nyet known.\n\n.. versionadded:: 3.8', 'filePath': 'Path to file, if uri is associated with a file.\n\n.. versionadded:: 3.22'} + QgsMimeDataUtils.Uri.__attribute_docs__ = {'layerType': 'Type of URI.\n\nRecognized types include\n\n- "vector": vector layers\n- "raster": raster layers\n- "mesh": mesh layers\n- "pointcloud": point cloud layers\n- "vector-tile": vector tile layers\n- "tiled-scene": tiled scene layers\n- "annotation": annotation layers\n- "group": group layers\n- "plugin": plugin layers\n- "custom": custom types\n- "project": QGS/QGZ project file\n- "directory": directory path\n\nNote: use :py:func:`QgsMapLayerFactory.typeToString()` to convert from a\n:py:class:`Qgis`.LayerType to a string (except for "custom", "project" and\n"directory")\n\nMime data from plugins may use additional custom layer types.', 'providerKey': 'For "vector" / "raster" type: provider id.\nFor "plugin" type: plugin layer type name.\nFor "custom" type: key of its :py:class:`QgsCustomDropHandler`\nFor "project" and "directory" types: unused', 'name': 'Human readable name to be used e.g. in layer tree', 'uri': 'Identifier of the data source recognized by its providerKey', 'layerId': 'Layer ID, if uri is associated with a layer from a :py:class:`QgsProject`.\n\n.. versionadded:: 3.8', 'pId': 'Unique ID associated with application instance. Can be used to identify\nif mime data was created inside the current application instance or not.\n\n.. versionadded:: 3.8', 'wkbType': 'WKB type, if associated with a vector layer, or :py:class:`QgsWkbTypes`.Unknown if not\nyet known.\n\n.. versionadded:: 3.8', 'filePath': 'Path to file, if uri is associated with a file.\n\n.. versionadded:: 3.22'} except (NameError, AttributeError): pass try: diff --git a/python/core/auto_additions/qgsmimedatautils.py b/python/core/auto_additions/qgsmimedatautils.py index 551f882dfd1b3..2bc2b665a9ffc 100644 --- a/python/core/auto_additions/qgsmimedatautils.py +++ b/python/core/auto_additions/qgsmimedatautils.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/qgsmimedatautils.h try: - QgsMimeDataUtils.Uri.__attribute_docs__ = {'layerType': 'Type of URI.\n\nRecognized types include\n\n- "vector": vector layers\n- "raster": raster layers\n- "mesh": mesh layers\n- "pointcloud": point cloud layers\n- "vector-tile": vector tile layers\n- "tiled-scene": tiled scene layers\n- "plugin": plugin layers\n- "custom": custom types\n- "project": QGS/QGZ project file\n- "directory": directory path\n\nMime data from plugins may use additional custom layer types.', 'providerKey': 'For "vector" / "raster" type: provider id.\nFor "plugin" type: plugin layer type name.\nFor "custom" type: key of its :py:class:`QgsCustomDropHandler`\nFor "project" and "directory" types: unused', 'name': 'Human readable name to be used e.g. in layer tree', 'uri': 'Identifier of the data source recognized by its providerKey', 'layerId': 'Layer ID, if uri is associated with a layer from a :py:class:`QgsProject`.\n\n.. versionadded:: 3.8', 'pId': 'Unique ID associated with application instance. Can be used to identify\nif mime data was created inside the current application instance or not.\n\n.. versionadded:: 3.8', 'wkbType': 'WKB type, if associated with a vector layer, or :py:class:`QgsWkbTypes`.Unknown if not\nyet known.\n\n.. versionadded:: 3.8', 'filePath': 'Path to file, if uri is associated with a file.\n\n.. versionadded:: 3.22'} + QgsMimeDataUtils.Uri.__attribute_docs__ = {'layerType': 'Type of URI.\n\nRecognized types include\n\n- "vector": vector layers\n- "raster": raster layers\n- "mesh": mesh layers\n- "pointcloud": point cloud layers\n- "vector-tile": vector tile layers\n- "tiled-scene": tiled scene layers\n- "annotation": annotation layers\n- "group": group layers\n- "plugin": plugin layers\n- "custom": custom types\n- "project": QGS/QGZ project file\n- "directory": directory path\n\nNote: use :py:func:`QgsMapLayerFactory.typeToString()` to convert from a\n:py:class:`Qgis`.LayerType to a string (except for "custom", "project" and\n"directory")\n\nMime data from plugins may use additional custom layer types.', 'providerKey': 'For "vector" / "raster" type: provider id.\nFor "plugin" type: plugin layer type name.\nFor "custom" type: key of its :py:class:`QgsCustomDropHandler`\nFor "project" and "directory" types: unused', 'name': 'Human readable name to be used e.g. in layer tree', 'uri': 'Identifier of the data source recognized by its providerKey', 'layerId': 'Layer ID, if uri is associated with a layer from a :py:class:`QgsProject`.\n\n.. versionadded:: 3.8', 'pId': 'Unique ID associated with application instance. Can be used to identify\nif mime data was created inside the current application instance or not.\n\n.. versionadded:: 3.8', 'wkbType': 'WKB type, if associated with a vector layer, or :py:class:`QgsWkbTypes`.Unknown if not\nyet known.\n\n.. versionadded:: 3.8', 'filePath': 'Path to file, if uri is associated with a file.\n\n.. versionadded:: 3.22'} except (NameError, AttributeError): pass try: diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 942dd528a8b53..b94d4964fcf0b 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -95,6 +95,7 @@ #include "qgsauxiliarystorage.h" #include "qgsvectortileutils.h" #include "qgsscaleutils.h" +#include "qgsmaplayerfactory.h" #include "qgsbrowserwidget.h" #include "annotations/qgsannotationitempropertieswidget.h" @@ -2447,6 +2448,8 @@ QList QgisApp::handleDropUriList( const QgsMimeDataUtils::UriList const QgsMimeDataUtils::Uri &u = lst.at( i ); QString uri = crsAndFormatAdjustedLayerUri( u.uri, u.supportedCrs, u.supportedFormats ); + bool ok = false; + Qgis::LayerType layerType = QgsMapLayerFactory::typeFromString( u.layerType, ok ); if ( u.layerType == QLatin1String( "collection" ) ) { @@ -2455,7 +2458,7 @@ QList QgisApp::handleDropUriList( const QgsMimeDataUtils::UriList if ( ok ) addedLayers.append( collectionLayers ); } - else if ( u.layerType == QLatin1String( "vector" ) ) + else if ( ok && layerType == Qgis::LayerType::Vector ) { const QList layerList { QgsAppLayerHandling::addVectorLayer( uri, u.name, u.providerKey, addToLegend ) }; for ( QgsVectorLayer *layer : std::as_const( layerList ) ) @@ -2463,7 +2466,7 @@ QList QgisApp::handleDropUriList( const QgsMimeDataUtils::UriList addedLayers << layer; } } - else if ( u.layerType == QLatin1String( "raster" ) ) + else if ( ok && layerType == Qgis::LayerType::Raster ) { const QList layerList { QgsAppLayerHandling::addRasterLayer( uri, u.name, u.providerKey, addToLegend ) }; for ( QgsRasterLayer *layer : std::as_const( layerList ) ) @@ -2471,7 +2474,7 @@ QList QgisApp::handleDropUriList( const QgsMimeDataUtils::UriList addedLayers << layer; } } - else if ( u.layerType == QLatin1String( "mesh" ) ) + else if ( ok && layerType == Qgis::LayerType::Mesh ) { const QList layerList { QgsAppLayerHandling::addMeshLayer( uri, u.name, u.providerKey, addToLegend ) }; for ( QgsMeshLayer *layer : std::as_const( layerList ) ) @@ -2479,17 +2482,17 @@ QList QgisApp::handleDropUriList( const QgsMimeDataUtils::UriList addedLayers << layer; } } - else if ( u.layerType == QLatin1String( "pointcloud" ) ) + else if ( ok && layerType == Qgis::LayerType::PointCloud ) { if ( QgsMapLayer *layer = QgsAppLayerHandling::addLayer( uri, u.name, u.providerKey, addToLegend ) ) addedLayers << layer; } - else if ( u.layerType == QLatin1String( "tiled-scene" ) ) + else if ( ok && layerType == Qgis::LayerType::TiledScene ) { if ( QgsMapLayer *layer = QgsAppLayerHandling::addLayer( uri, u.name, u.providerKey, addToLegend ) ) addedLayers << layer; } - else if ( u.layerType == QLatin1String( "vector-tile" ) ) + else if ( ok && layerType == Qgis::LayerType::VectorTile ) { QgsTemporaryCursorOverride busyCursor( Qt::WaitCursor ); @@ -2587,7 +2590,7 @@ QList QgisApp::handleDropUriList( const QgsMimeDataUtils::UriList addedLayers << layer; } } - else if ( u.layerType == QLatin1String( "plugin" ) ) + else if ( ok && layerType == Qgis::LayerType::Plugin ) { QgsMapLayer *layer = QgsAppLayerHandling::addLayer( uri, u.name, u.providerKey, addToLegend, false ); if ( layer ) diff --git a/src/core/browser/qgslayeritem.cpp b/src/core/browser/qgslayeritem.cpp index 7ba9fff15bb70..94a4fc9b4d6db 100644 --- a/src/core/browser/qgslayeritem.cpp +++ b/src/core/browser/qgslayeritem.cpp @@ -18,6 +18,7 @@ #include "qgslayeritem.h" #include "moc_qgslayeritem.cpp" #include "qgsmaplayer.h" +#include "qgsmaplayerfactory.h" #include "qgsvectorlayer.h" #include "qgsiconutils.h" @@ -243,11 +244,11 @@ bool QgsLayerItem::equal( const QgsDataItem *other ) QgsMimeDataUtils::UriList QgsLayerItem::mimeUris() const { QgsMimeDataUtils::Uri u; + u.layerType = QgsMapLayerFactory::typeToString( mapLayerType() ); switch ( mapLayerType() ) { case Qgis::LayerType::Vector: - u.layerType = QStringLiteral( "vector" ); switch ( mLayerType ) { case Qgis::BrowserLayerType::Point: @@ -277,28 +278,13 @@ QgsMimeDataUtils::UriList QgsLayerItem::mimeUris() const } break; case Qgis::LayerType::Raster: - u.layerType = QStringLiteral( "raster" ); - break; case Qgis::LayerType::Mesh: - u.layerType = QStringLiteral( "mesh" ); - break; case Qgis::LayerType::VectorTile: - u.layerType = QStringLiteral( "vector-tile" ); - break; case Qgis::LayerType::PointCloud: - u.layerType = QStringLiteral( "pointcloud" ); - break; case Qgis::LayerType::TiledScene: - u.layerType = QStringLiteral( "tiled-scene" ); - break; case Qgis::LayerType::Plugin: - u.layerType = QStringLiteral( "plugin" ); - break; case Qgis::LayerType::Group: - u.layerType = QStringLiteral( "group" ); - break; case Qgis::LayerType::Annotation: - u.layerType = QStringLiteral( "annotation" ); break; } diff --git a/src/core/providers/qgsprovidersublayerdetails.cpp b/src/core/providers/qgsprovidersublayerdetails.cpp index 02c621ddc54c9..fabab7a1aca8c 100644 --- a/src/core/providers/qgsprovidersublayerdetails.cpp +++ b/src/core/providers/qgsprovidersublayerdetails.cpp @@ -30,35 +30,20 @@ QgsMapLayer *QgsProviderSublayerDetails::toLayer( const LayerOptions &options ) QgsMimeDataUtils::Uri QgsProviderSublayerDetails::toMimeUri() const { QgsMimeDataUtils::Uri u; + u.layerType = QgsMapLayerFactory::typeToString( mType ); switch ( mType ) { case Qgis::LayerType::Vector: - u.layerType = QStringLiteral( "vector" ); u.wkbType = mWkbType; break; case Qgis::LayerType::Raster: - u.layerType = QStringLiteral( "raster" ); - break; case Qgis::LayerType::Mesh: - u.layerType = QStringLiteral( "mesh" ); - break; case Qgis::LayerType::VectorTile: - u.layerType = QStringLiteral( "vector-tile" ); - break; case Qgis::LayerType::PointCloud: - u.layerType = QStringLiteral( "pointcloud" ); - break; case Qgis::LayerType::Plugin: - u.layerType = QStringLiteral( "plugin" ); - break; case Qgis::LayerType::Group: - u.layerType = QStringLiteral( "group" ); - break; case Qgis::LayerType::Annotation: - u.layerType = QStringLiteral( "annotation" ); - break; case Qgis::LayerType::TiledScene: - u.layerType = QStringLiteral( "tiled-scene" ); break; } diff --git a/src/core/qgsmimedatautils.cpp b/src/core/qgsmimedatautils.cpp index 6ad3b74581848..528fe7c210fe5 100644 --- a/src/core/qgsmimedatautils.cpp +++ b/src/core/qgsmimedatautils.cpp @@ -20,6 +20,7 @@ #include "qgslogger.h" #include "qgsrasterlayer.h" #include "qgsvectorlayer.h" +#include "qgsmaplayerfactory.h" #include "qgsmeshlayer.h" #include @@ -71,38 +72,20 @@ QgsMimeDataUtils::Uri::Uri( QgsMapLayer *layer ) , layerId( layer->id() ) , pId( QString::number( QCoreApplication::applicationPid() ) ) { + layerType = QgsMapLayerFactory::typeToString( layer->type() ); switch ( layer->type() ) { case Qgis::LayerType::Vector: { - layerType = QStringLiteral( "vector" ); wkbType = qobject_cast< QgsVectorLayer *>( layer )->wkbType(); break; } case Qgis::LayerType::Raster: - { - layerType = QStringLiteral( "raster" ); - break; - } - case Qgis::LayerType::Mesh: - { - layerType = QStringLiteral( "mesh" ); - break; - } case Qgis::LayerType::PointCloud: - { - layerType = QStringLiteral( "pointcloud" ); - break; - } case Qgis::LayerType::VectorTile: - { - layerType = QStringLiteral( "vector-tile" ); - break; - } case Qgis::LayerType::TiledScene: { - layerType = QStringLiteral( "tiled-scene" ); break; } diff --git a/src/core/qgsmimedatautils.h b/src/core/qgsmimedatautils.h index 2289a7a8cd628..c35248d46040f 100644 --- a/src/core/qgsmimedatautils.h +++ b/src/core/qgsmimedatautils.h @@ -103,11 +103,17 @@ class CORE_EXPORT QgsMimeDataUtils * - "pointcloud": point cloud layers * - "vector-tile": vector tile layers * - "tiled-scene": tiled scene layers + * - "annotation": annotation layers + * - "group": group layers * - "plugin": plugin layers * - "custom": custom types * - "project": QGS/QGZ project file * - "directory": directory path * + * Note: use QgsMapLayerFactory::typeToString() to convert from a + * Qgis::LayerType to a string (except for "custom", "project" and + * "directory") + * * Mime data from plugins may use additional custom layer types. */ QString layerType; diff --git a/src/gui/processing/qgsprocessingmultipleselectiondialog.cpp b/src/gui/processing/qgsprocessingmultipleselectiondialog.cpp index f37b255cf0e2f..ab51eb3f6553c 100644 --- a/src/gui/processing/qgsprocessingmultipleselectiondialog.cpp +++ b/src/gui/processing/qgsprocessingmultipleselectiondialog.cpp @@ -19,6 +19,7 @@ #include "qgssettings.h" #include "qgsfileutils.h" #include "qgsvectorlayer.h" +#include "qgsmaplayerfactory.h" #include "qgsmeshlayer.h" #include "qgsrasterlayer.h" #include "qgspluginlayer.h" @@ -460,7 +461,7 @@ QStringList QgsProcessingMultipleInputPanelWidget::compatibleUrisFromMimeData( c || parameter->layerType() == Qgis::ProcessingSourceType::VectorLine || parameter->layerType() == Qgis::ProcessingSourceType::VectorPoint || parameter->layerType() == Qgis::ProcessingSourceType::VectorPolygon ) - && u.layerType == QLatin1String( "vector" ) ) + && u.layerType == QgsMapLayerFactory::typeToString( Qgis::LayerType::Vector ) ) { bool acceptable = false; switch ( QgsWkbTypes::geometryType( u.wkbType ) ) @@ -493,16 +494,16 @@ QStringList QgsProcessingMultipleInputPanelWidget::compatibleUrisFromMimeData( c res.append( u.providerKey != QLatin1String( "ogr" ) ? QgsProcessingUtils::encodeProviderKeyAndUri( u.providerKey, u.uri ) : u.uri ); } else if ( ( parameter->layerType() == Qgis::ProcessingSourceType::MapLayer || parameter->layerType() == Qgis::ProcessingSourceType::Raster ) - && u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" ) ) + && u.layerType == QgsMapLayerFactory::typeToString( Qgis::LayerType::Raster ) && u.providerKey == QLatin1String( "gdal" ) ) res.append( u.uri ); else if ( ( parameter->layerType() == Qgis::ProcessingSourceType::MapLayer || parameter->layerType() == Qgis::ProcessingSourceType::Mesh ) - && u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" ) ) + && u.layerType == QgsMapLayerFactory::typeToString( Qgis::LayerType::Mesh ) && u.providerKey == QLatin1String( "mdal" ) ) res.append( u.uri ); else if ( ( parameter->layerType() == Qgis::ProcessingSourceType::MapLayer || parameter->layerType() == Qgis::ProcessingSourceType::PointCloud ) - && u.layerType == QLatin1String( "pointcloud" ) ) + && u.layerType == QgsMapLayerFactory::typeToString( Qgis::LayerType::PointCloud ) ) res.append( u.uri ); else if ( ( parameter->layerType() == Qgis::ProcessingSourceType::MapLayer || parameter->layerType() == Qgis::ProcessingSourceType::VectorTile ) - && u.layerType == QLatin1String( "vector-tile" ) ) + && u.layerType == QgsMapLayerFactory::typeToString( Qgis::LayerType::VectorTile ) ) res.append( u.uri ); // NOLINTEND(bugprone-branch-clone) } From 530eb4bc2f7933b2b5ceb5c601c9dfae27ea6f77 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 31 Jan 2025 15:30:45 +0100 Subject: [PATCH 70/81] Test and code adjustments related to MIME type serialization for PointCloudLayer going from 'pointcloud' to 'point-cloud' --- python/PyQt6/core/auto_additions/qgsmimedatautils.py | 2 +- python/core/auto_additions/qgsmimedatautils.py | 2 +- src/core/qgsmaplayerfactory.cpp | 6 +++++- src/core/qgsmimedatautils.h | 2 +- tests/src/python/test_qgsprovidersublayerdetails.py | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/python/PyQt6/core/auto_additions/qgsmimedatautils.py b/python/PyQt6/core/auto_additions/qgsmimedatautils.py index 2bc2b665a9ffc..8a8d3661c4992 100644 --- a/python/PyQt6/core/auto_additions/qgsmimedatautils.py +++ b/python/PyQt6/core/auto_additions/qgsmimedatautils.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/qgsmimedatautils.h try: - QgsMimeDataUtils.Uri.__attribute_docs__ = {'layerType': 'Type of URI.\n\nRecognized types include\n\n- "vector": vector layers\n- "raster": raster layers\n- "mesh": mesh layers\n- "pointcloud": point cloud layers\n- "vector-tile": vector tile layers\n- "tiled-scene": tiled scene layers\n- "annotation": annotation layers\n- "group": group layers\n- "plugin": plugin layers\n- "custom": custom types\n- "project": QGS/QGZ project file\n- "directory": directory path\n\nNote: use :py:func:`QgsMapLayerFactory.typeToString()` to convert from a\n:py:class:`Qgis`.LayerType to a string (except for "custom", "project" and\n"directory")\n\nMime data from plugins may use additional custom layer types.', 'providerKey': 'For "vector" / "raster" type: provider id.\nFor "plugin" type: plugin layer type name.\nFor "custom" type: key of its :py:class:`QgsCustomDropHandler`\nFor "project" and "directory" types: unused', 'name': 'Human readable name to be used e.g. in layer tree', 'uri': 'Identifier of the data source recognized by its providerKey', 'layerId': 'Layer ID, if uri is associated with a layer from a :py:class:`QgsProject`.\n\n.. versionadded:: 3.8', 'pId': 'Unique ID associated with application instance. Can be used to identify\nif mime data was created inside the current application instance or not.\n\n.. versionadded:: 3.8', 'wkbType': 'WKB type, if associated with a vector layer, or :py:class:`QgsWkbTypes`.Unknown if not\nyet known.\n\n.. versionadded:: 3.8', 'filePath': 'Path to file, if uri is associated with a file.\n\n.. versionadded:: 3.22'} + QgsMimeDataUtils.Uri.__attribute_docs__ = {'layerType': 'Type of URI.\n\nRecognized types include\n\n- "vector": vector layers\n- "raster": raster layers\n- "mesh": mesh layers\n- "point-cloud": point cloud layers (spelled with a dash since QGIS 3.42.0. In prior versions, there was no dash)\n- "vector-tile": vector tile layers\n- "tiled-scene": tiled scene layers\n- "annotation": annotation layers\n- "group": group layers\n- "plugin": plugin layers\n- "custom": custom types\n- "project": QGS/QGZ project file\n- "directory": directory path\n\nNote: use :py:func:`QgsMapLayerFactory.typeToString()` to convert from a\n:py:class:`Qgis`.LayerType to a string (except for "custom", "project" and\n"directory")\n\nMime data from plugins may use additional custom layer types.', 'providerKey': 'For "vector" / "raster" type: provider id.\nFor "plugin" type: plugin layer type name.\nFor "custom" type: key of its :py:class:`QgsCustomDropHandler`\nFor "project" and "directory" types: unused', 'name': 'Human readable name to be used e.g. in layer tree', 'uri': 'Identifier of the data source recognized by its providerKey', 'layerId': 'Layer ID, if uri is associated with a layer from a :py:class:`QgsProject`.\n\n.. versionadded:: 3.8', 'pId': 'Unique ID associated with application instance. Can be used to identify\nif mime data was created inside the current application instance or not.\n\n.. versionadded:: 3.8', 'wkbType': 'WKB type, if associated with a vector layer, or :py:class:`QgsWkbTypes`.Unknown if not\nyet known.\n\n.. versionadded:: 3.8', 'filePath': 'Path to file, if uri is associated with a file.\n\n.. versionadded:: 3.22'} except (NameError, AttributeError): pass try: diff --git a/python/core/auto_additions/qgsmimedatautils.py b/python/core/auto_additions/qgsmimedatautils.py index 2bc2b665a9ffc..8a8d3661c4992 100644 --- a/python/core/auto_additions/qgsmimedatautils.py +++ b/python/core/auto_additions/qgsmimedatautils.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/qgsmimedatautils.h try: - QgsMimeDataUtils.Uri.__attribute_docs__ = {'layerType': 'Type of URI.\n\nRecognized types include\n\n- "vector": vector layers\n- "raster": raster layers\n- "mesh": mesh layers\n- "pointcloud": point cloud layers\n- "vector-tile": vector tile layers\n- "tiled-scene": tiled scene layers\n- "annotation": annotation layers\n- "group": group layers\n- "plugin": plugin layers\n- "custom": custom types\n- "project": QGS/QGZ project file\n- "directory": directory path\n\nNote: use :py:func:`QgsMapLayerFactory.typeToString()` to convert from a\n:py:class:`Qgis`.LayerType to a string (except for "custom", "project" and\n"directory")\n\nMime data from plugins may use additional custom layer types.', 'providerKey': 'For "vector" / "raster" type: provider id.\nFor "plugin" type: plugin layer type name.\nFor "custom" type: key of its :py:class:`QgsCustomDropHandler`\nFor "project" and "directory" types: unused', 'name': 'Human readable name to be used e.g. in layer tree', 'uri': 'Identifier of the data source recognized by its providerKey', 'layerId': 'Layer ID, if uri is associated with a layer from a :py:class:`QgsProject`.\n\n.. versionadded:: 3.8', 'pId': 'Unique ID associated with application instance. Can be used to identify\nif mime data was created inside the current application instance or not.\n\n.. versionadded:: 3.8', 'wkbType': 'WKB type, if associated with a vector layer, or :py:class:`QgsWkbTypes`.Unknown if not\nyet known.\n\n.. versionadded:: 3.8', 'filePath': 'Path to file, if uri is associated with a file.\n\n.. versionadded:: 3.22'} + QgsMimeDataUtils.Uri.__attribute_docs__ = {'layerType': 'Type of URI.\n\nRecognized types include\n\n- "vector": vector layers\n- "raster": raster layers\n- "mesh": mesh layers\n- "point-cloud": point cloud layers (spelled with a dash since QGIS 3.42.0. In prior versions, there was no dash)\n- "vector-tile": vector tile layers\n- "tiled-scene": tiled scene layers\n- "annotation": annotation layers\n- "group": group layers\n- "plugin": plugin layers\n- "custom": custom types\n- "project": QGS/QGZ project file\n- "directory": directory path\n\nNote: use :py:func:`QgsMapLayerFactory.typeToString()` to convert from a\n:py:class:`Qgis`.LayerType to a string (except for "custom", "project" and\n"directory")\n\nMime data from plugins may use additional custom layer types.', 'providerKey': 'For "vector" / "raster" type: provider id.\nFor "plugin" type: plugin layer type name.\nFor "custom" type: key of its :py:class:`QgsCustomDropHandler`\nFor "project" and "directory" types: unused', 'name': 'Human readable name to be used e.g. in layer tree', 'uri': 'Identifier of the data source recognized by its providerKey', 'layerId': 'Layer ID, if uri is associated with a layer from a :py:class:`QgsProject`.\n\n.. versionadded:: 3.8', 'pId': 'Unique ID associated with application instance. Can be used to identify\nif mime data was created inside the current application instance or not.\n\n.. versionadded:: 3.8', 'wkbType': 'WKB type, if associated with a vector layer, or :py:class:`QgsWkbTypes`.Unknown if not\nyet known.\n\n.. versionadded:: 3.8', 'filePath': 'Path to file, if uri is associated with a file.\n\n.. versionadded:: 3.22'} except (NameError, AttributeError): pass try: diff --git a/src/core/qgsmaplayerfactory.cpp b/src/core/qgsmaplayerfactory.cpp index ddf42af3aeb93..b5a260226857d 100644 --- a/src/core/qgsmaplayerfactory.cpp +++ b/src/core/qgsmaplayerfactory.cpp @@ -36,7 +36,11 @@ Qgis::LayerType QgsMapLayerFactory::typeFromString( const QString &string, bool return Qgis::LayerType::Mesh; else if ( string.compare( QLatin1String( "vector-tile" ), Qt::CaseInsensitive ) == 0 ) return Qgis::LayerType::VectorTile; - else if ( string.compare( QLatin1String( "point-cloud" ), Qt::CaseInsensitive ) == 0 ) + else if ( string.compare( QLatin1String( "point-cloud" ), Qt::CaseInsensitive ) == 0 || + // We accept "pointcloud" for backward compatibility with the + // MIME related code, which spelled it that way before 3.42.0 where + // we have delegated to QgsMapLayerFactory::typeToString() + string.compare( QLatin1String( "pointcloud" ), Qt::CaseInsensitive ) == 0 ) return Qgis::LayerType::PointCloud; else if ( string.compare( QLatin1String( "plugin" ), Qt::CaseInsensitive ) == 0 ) return Qgis::LayerType::Plugin; diff --git a/src/core/qgsmimedatautils.h b/src/core/qgsmimedatautils.h index c35248d46040f..e14fba5313928 100644 --- a/src/core/qgsmimedatautils.h +++ b/src/core/qgsmimedatautils.h @@ -100,7 +100,7 @@ class CORE_EXPORT QgsMimeDataUtils * - "vector": vector layers * - "raster": raster layers * - "mesh": mesh layers - * - "pointcloud": point cloud layers + * - "point-cloud": point cloud layers (spelled with a dash since QGIS 3.42.0. In prior versions, there was no dash) * - "vector-tile": vector tile layers * - "tiled-scene": tiled scene layers * - "annotation": annotation layers diff --git a/tests/src/python/test_qgsprovidersublayerdetails.py b/tests/src/python/test_qgsprovidersublayerdetails.py index 0812b281a37f2..c9577fc28f17a 100644 --- a/tests/src/python/test_qgsprovidersublayerdetails.py +++ b/tests/src/python/test_qgsprovidersublayerdetails.py @@ -201,7 +201,7 @@ def test_to_mime(self): details.setType(QgsMapLayerType.PointCloudLayer) uri = details.toMimeUri() - self.assertEqual(uri.layerType, "pointcloud") + self.assertEqual(uri.layerType, "point-cloud") details.setType(QgsMapLayerType.PluginLayer) uri = details.toMimeUri() From f24a5c44b8cb20155d5d168a39d1bf6e86a134a2 Mon Sep 17 00:00:00 2001 From: qgis-bot Date: Sun, 2 Feb 2025 21:54:44 +0000 Subject: [PATCH 71/81] =?UTF-8?q?auto=20sipify=20=F0=9F=8D=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/PyQt6/core/class_map.yaml | 12 ++++++------ python/core/class_map.yaml | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/python/PyQt6/core/class_map.yaml b/python/PyQt6/core/class_map.yaml index 30c3924f083d5..7145a1807bf62 100644 --- a/python/PyQt6/core/class_map.yaml +++ b/python/PyQt6/core/class_map.yaml @@ -10317,18 +10317,18 @@ QgsMetadataUtils.convertFromEsri: src/core/metadata/qgsmetadatautils.h#L41 QgsMetadataUtils: src/core/metadata/qgsmetadatautils.h#L34 QgsMimeDataUtils.QgsMimeDataUtils.Uri: src/core/qgsmimedatautils.h#L46 QgsMimeDataUtils.QgsMimeDataUtils.Uri: src/core/qgsmimedatautils.h#L53 -QgsMimeDataUtils.QgsMimeDataUtils.__repr__: src/core/qgsmimedatautils.h#L158 +QgsMimeDataUtils.QgsMimeDataUtils.__repr__: src/core/qgsmimedatautils.h#L164 QgsMimeDataUtils.QgsMimeDataUtils.data: src/core/qgsmimedatautils.h#L61 QgsMimeDataUtils.QgsMimeDataUtils.isValid: src/core/qgsmimedatautils.h#L58 QgsMimeDataUtils.QgsMimeDataUtils.mapLayer: src/core/qgsmimedatautils.h#L93 QgsMimeDataUtils.QgsMimeDataUtils.meshLayer: src/core/qgsmimedatautils.h#L82 QgsMimeDataUtils.QgsMimeDataUtils.rasterLayer: src/core/qgsmimedatautils.h#L75 QgsMimeDataUtils.QgsMimeDataUtils.vectorLayer: src/core/qgsmimedatautils.h#L68 -QgsMimeDataUtils.decodeUriList: src/core/qgsmimedatautils.h#L174 -QgsMimeDataUtils.encodeUriList: src/core/qgsmimedatautils.h#L170 -QgsMimeDataUtils.hasOriginatedFromCurrentAppInstance: src/core/qgsmimedatautils.h#L187 -QgsMimeDataUtils.isUriList: src/core/qgsmimedatautils.h#L172 -QgsMimeDataUtils.layerTreeNodesToUriList: src/core/qgsmimedatautils.h#L179 +QgsMimeDataUtils.decodeUriList: src/core/qgsmimedatautils.h#L180 +QgsMimeDataUtils.encodeUriList: src/core/qgsmimedatautils.h#L176 +QgsMimeDataUtils.hasOriginatedFromCurrentAppInstance: src/core/qgsmimedatautils.h#L193 +QgsMimeDataUtils.isUriList: src/core/qgsmimedatautils.h#L178 +QgsMimeDataUtils.layerTreeNodesToUriList: src/core/qgsmimedatautils.h#L185 QgsMimeDataUtils: src/core/qgsmimedatautils.h#L37 QgsMultiBandColorRenderer.block: src/core/raster/qgsmultibandcolorrenderer.h#L50 QgsMultiBandColorRenderer.blueBand: src/core/raster/qgsmultibandcolorrenderer.h#L56 diff --git a/python/core/class_map.yaml b/python/core/class_map.yaml index 6b80f2477c201..c5eb4c922425c 100644 --- a/python/core/class_map.yaml +++ b/python/core/class_map.yaml @@ -10317,18 +10317,18 @@ QgsMetadataUtils.convertFromEsri: src/core/metadata/qgsmetadatautils.h#L41 QgsMetadataUtils: src/core/metadata/qgsmetadatautils.h#L34 QgsMimeDataUtils.QgsMimeDataUtils.Uri: src/core/qgsmimedatautils.h#L46 QgsMimeDataUtils.QgsMimeDataUtils.Uri: src/core/qgsmimedatautils.h#L53 -QgsMimeDataUtils.QgsMimeDataUtils.__repr__: src/core/qgsmimedatautils.h#L158 +QgsMimeDataUtils.QgsMimeDataUtils.__repr__: src/core/qgsmimedatautils.h#L164 QgsMimeDataUtils.QgsMimeDataUtils.data: src/core/qgsmimedatautils.h#L61 QgsMimeDataUtils.QgsMimeDataUtils.isValid: src/core/qgsmimedatautils.h#L58 QgsMimeDataUtils.QgsMimeDataUtils.mapLayer: src/core/qgsmimedatautils.h#L93 QgsMimeDataUtils.QgsMimeDataUtils.meshLayer: src/core/qgsmimedatautils.h#L82 QgsMimeDataUtils.QgsMimeDataUtils.rasterLayer: src/core/qgsmimedatautils.h#L75 QgsMimeDataUtils.QgsMimeDataUtils.vectorLayer: src/core/qgsmimedatautils.h#L68 -QgsMimeDataUtils.decodeUriList: src/core/qgsmimedatautils.h#L174 -QgsMimeDataUtils.encodeUriList: src/core/qgsmimedatautils.h#L170 -QgsMimeDataUtils.hasOriginatedFromCurrentAppInstance: src/core/qgsmimedatautils.h#L187 -QgsMimeDataUtils.isUriList: src/core/qgsmimedatautils.h#L172 -QgsMimeDataUtils.layerTreeNodesToUriList: src/core/qgsmimedatautils.h#L179 +QgsMimeDataUtils.decodeUriList: src/core/qgsmimedatautils.h#L180 +QgsMimeDataUtils.encodeUriList: src/core/qgsmimedatautils.h#L176 +QgsMimeDataUtils.hasOriginatedFromCurrentAppInstance: src/core/qgsmimedatautils.h#L193 +QgsMimeDataUtils.isUriList: src/core/qgsmimedatautils.h#L178 +QgsMimeDataUtils.layerTreeNodesToUriList: src/core/qgsmimedatautils.h#L185 QgsMimeDataUtils: src/core/qgsmimedatautils.h#L37 QgsMultiBandColorRenderer.block: src/core/raster/qgsmultibandcolorrenderer.h#L50 QgsMultiBandColorRenderer.blueBand: src/core/raster/qgsmultibandcolorrenderer.h#L56 From 5e324efba8f435e6ab2a58008152a65150352503 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Sun, 2 Feb 2025 16:22:12 +0700 Subject: [PATCH 72/81] [ui] Fix missing @cluster_size and @cluster_color variables not visible when editing the cluster renderer's cluster symbol --- src/gui/symbology/qgspointclusterrendererwidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/symbology/qgspointclusterrendererwidget.cpp b/src/gui/symbology/qgspointclusterrendererwidget.cpp index eec2d94340b7d..a8ffb60bdc52c 100644 --- a/src/gui/symbology/qgspointclusterrendererwidget.cpp +++ b/src/gui/symbology/qgspointclusterrendererwidget.cpp @@ -212,6 +212,7 @@ QgsExpressionContext QgsPointClusterRendererWidget::createExpressionContext() co { context << new QgsExpressionContextScope( s ); } + context.setHighlightedVariables( QStringList() << QgsExpressionContext::EXPR_CLUSTER_COLOR << QgsExpressionContext::EXPR_CLUSTER_SIZE ); return context; } From 1907ab32fe4cba9628f70f459adbc0a743184c4a Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 31 Jan 2025 18:01:18 +0100 Subject: [PATCH 73/81] QgsMapLayer::publicSource(): make it redact/remove GDAL credentials Fixes #60292 --- .../core/auto_generated/qgsmaplayer.sip.in | 3 +- python/core/auto_generated/qgsmaplayer.sip.in | 3 +- src/core/qgsmaplayer.cpp | 36 ++++++++++++++++--- src/core/qgsmaplayer.h | 11 +++--- tests/src/core/testqgsmaplayer.cpp | 13 +++++++ 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/python/PyQt6/core/auto_generated/qgsmaplayer.sip.in b/python/PyQt6/core/auto_generated/qgsmaplayer.sip.in index 73545c5cd377d..f185105e38a34 100644 --- a/python/PyQt6/core/auto_generated/qgsmaplayer.sip.in +++ b/python/PyQt6/core/auto_generated/qgsmaplayer.sip.in @@ -567,13 +567,14 @@ or other problem. Child classes set this flag when initialized. :return: ``True`` if the layer is valid and can be accessed %End + QString publicSource( bool hidePassword = false ) const; %Docstring Gets a version of the internal layer definition that has sensitive bits removed (for example, the password). This function should be used when displaying the source name for general viewing. -:param hidePassword: False, if the password should be removed or replaced by an arbitrary string, since QGIS 3.34 +:param hidePassword: ``True`` to replace the value of credentials with 'xxxxxxxx', ``False`` to completely remove credentials (key and value). Since QGIS 3.34 .. seealso:: :py:func:`source` %End diff --git a/python/core/auto_generated/qgsmaplayer.sip.in b/python/core/auto_generated/qgsmaplayer.sip.in index cfa3b903874f7..41b536975391f 100644 --- a/python/core/auto_generated/qgsmaplayer.sip.in +++ b/python/core/auto_generated/qgsmaplayer.sip.in @@ -567,13 +567,14 @@ or other problem. Child classes set this flag when initialized. :return: ``True`` if the layer is valid and can be accessed %End + QString publicSource( bool hidePassword = false ) const; %Docstring Gets a version of the internal layer definition that has sensitive bits removed (for example, the password). This function should be used when displaying the source name for general viewing. -:param hidePassword: False, if the password should be removed or replaced by an arbitrary string, since QGIS 3.34 +:param hidePassword: ``True`` to replace the value of credentials with 'xxxxxxxx', ``False`` to completely remove credentials (key and value). Since QGIS 3.34 .. seealso:: :py:func:`source` %End diff --git a/src/core/qgsmaplayer.cpp b/src/core/qgsmaplayer.cpp index 4da4369fac02a..be80991c95095 100644 --- a/src/core/qgsmaplayer.cpp +++ b/src/core/qgsmaplayer.cpp @@ -473,13 +473,37 @@ QString QgsMapLayer::metadataUrlFormat() const } } -QString QgsMapLayer::publicSource( bool hidePassword ) const +QString QgsMapLayer::publicSource( bool redactCredentials ) const { QGIS_PROTECT_QOBJECT_THREAD_ACCESS + QString safeName = mDataSource; + + if ( providerType() == QLatin1String( "gdal" ) ) + { + QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType(), safeName ); + QVariantMap credentialOptions = components.value( QStringLiteral( "credentialOptions" ) ).toMap(); + if ( !credentialOptions.empty() ) + { + if ( redactCredentials ) + { + for ( auto it = credentialOptions.begin(); it != credentialOptions.end(); ++it ) + { + it.value() = QStringLiteral( "XXXXXXXX" ); + } + components.insert( QStringLiteral( "credentialOptions" ), credentialOptions ); + } + else + { + components.remove( QStringLiteral( "credentialOptions" ) ); + } + } + safeName = QgsProviderRegistry::instance()->encodeUri( providerType(), components ); + } + // Redo this every time we're asked for it, as we don't know if // dataSource has changed. - QString safeName = QgsDataSourceUri::removePassword( mDataSource, hidePassword ); + safeName = QgsDataSourceUri::removePassword( safeName, redactCredentials ); return safeName; } @@ -3228,12 +3252,14 @@ QString QgsMapLayer::generalHtmlMetadata() const // name metadata += QStringLiteral( "" ) + tr( "Name" ) + QStringLiteral( "" ) + name() + QStringLiteral( "\n" ); + const QString lPublicSource = publicSource(); + QString path; bool isLocalPath = false; if ( dataProvider() ) { // local path - QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( dataProvider()->name(), publicSource() ); + QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( dataProvider()->name(), lPublicSource ); if ( uriComponents.contains( QStringLiteral( "path" ) ) ) { path = uriComponents[QStringLiteral( "path" )].toString(); @@ -3279,8 +3305,8 @@ QString QgsMapLayer::generalHtmlMetadata() const } // data source - if ( publicSource() != path || !isLocalPath ) - metadata += QStringLiteral( "" ) + tr( "Source" ) + QStringLiteral( "%1" ).arg( publicSource() != path ? publicSource() : path ) + QStringLiteral( "\n" ); + if ( lPublicSource != path || !isLocalPath ) + metadata += QStringLiteral( "" ) + tr( "Source" ) + QStringLiteral( "%1" ).arg( lPublicSource != path ? lPublicSource : path ) + QStringLiteral( "\n" ); // provider if ( dataProvider() ) diff --git a/src/core/qgsmaplayer.h b/src/core/qgsmaplayer.h index 19303cb6e2127..861b2ffc5c0b7 100644 --- a/src/core/qgsmaplayer.h +++ b/src/core/qgsmaplayer.h @@ -573,12 +573,15 @@ class CORE_EXPORT QgsMapLayer : public QObject */ bool isValid() const; + // TODO QGIS 4.0: consider changing bool hidePassword to an enumeration: HIDE_CREDENTIALS / REDACT_CREDENTIALS + // to avoid the ambiguity of the double negation (hide = false) + /** * Gets a version of the internal layer definition that has sensitive - * bits removed (for example, the password). This function should - * be used when displaying the source name for general viewing. - * \param hidePassword False, if the password should be removed or replaced by an arbitrary string, since QGIS 3.34 - * \see source() + * bits removed (for example, the password). This function should + * be used when displaying the source name for general viewing. + * \param hidePassword TRUE to replace the value of credentials with 'xxxxxxxx', FALSE to completely remove credentials (key and value). Since QGIS 3.34 + * \see source() */ QString publicSource( bool hidePassword = false ) const; diff --git a/tests/src/core/testqgsmaplayer.cpp b/tests/src/core/testqgsmaplayer.cpp index 47e6f2d5a6e96..cad52331d7525 100644 --- a/tests/src/core/testqgsmaplayer.cpp +++ b/tests/src/core/testqgsmaplayer.cpp @@ -23,6 +23,7 @@ //qgis includes... #include +#include #include #include #include @@ -73,6 +74,8 @@ class TestQgsMapLayer : public QObject void readCustomProperties(); + void publicSourceOnGdalWithCredentials(); + private: QgsVectorLayer *mpLayer = nullptr; }; @@ -510,5 +513,15 @@ void TestQgsMapLayer::readCustomProperties() QCOMPARE( spy.at( 1 ).at( 0 ), "my_property_two" ); } +void TestQgsMapLayer::publicSourceOnGdalWithCredentials() +{ + QgsRasterLayer rl( + QStringLiteral( "test.tif|option:AN=OPTION|credential:SOMEKEY=AAAAA|credential:ANOTHER=BBB" ), QString(), QStringLiteral( "gdal" ) + ); + QCOMPARE( rl.publicSource( true ), QStringLiteral( "test.tif|option:AN=OPTION|credential:ANOTHER=XXXXXXXX|credential:SOMEKEY=XXXXXXXX" ) ); + QCOMPARE( rl.publicSource( false ), QStringLiteral( "test.tif|option:AN=OPTION" ) ); + QCOMPARE( rl.publicSource(), QStringLiteral( "test.tif|option:AN=OPTION" ) ); +} + QGSTEST_MAIN( TestQgsMapLayer ) #include "testqgsmaplayer.moc" From 775c2070a7b6a195d6e0f5e0226070742783fe06 Mon Sep 17 00:00:00 2001 From: qgis-bot Date: Sun, 2 Feb 2025 22:08:07 +0000 Subject: [PATCH 74/81] =?UTF-8?q?auto=20sipify=20=F0=9F=8D=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- python/PyQt6/core/class_map.yaml | 332 +++++++++++++++---------------- python/core/class_map.yaml | 332 +++++++++++++++---------------- 2 files changed, 332 insertions(+), 332 deletions(-) diff --git a/python/PyQt6/core/class_map.yaml b/python/PyQt6/core/class_map.yaml index 7145a1807bf62..a5c97e3165b65 100644 --- a/python/PyQt6/core/class_map.yaml +++ b/python/PyQt6/core/class_map.yaml @@ -8863,218 +8863,218 @@ QgsMapInfoSymbolConverter.convertFillSymbol: src/core/symbology/qgsmapinfosymbol QgsMapInfoSymbolConverter.convertLineSymbol: src/core/symbology/qgsmapinfosymbolconverter.h#L75 QgsMapInfoSymbolConverter.convertMarkerSymbol: src/core/symbology/qgsmapinfosymbolconverter.h#L91 QgsMapInfoSymbolConverter: src/core/symbology/qgsmapinfosymbolconverter.h#L66 -QgsMapLayer.__repr__: src/core/qgsmaplayer.h#L1893 +QgsMapLayer.__repr__: src/core/qgsmaplayer.h#L1896 QgsMapLayer.abstract: src/core/qgsmaplayer.h#L355 -QgsMapLayer.accept: src/core/qgsmaplayer.h#L1720 -QgsMapLayer.appendError: src/core/qgsmaplayer.h#L2257 +QgsMapLayer.accept: src/core/qgsmaplayer.h#L1723 +QgsMapLayer.appendError: src/core/qgsmaplayer.h#L2260 QgsMapLayer.attribution: src/core/qgsmaplayer.h#L411 QgsMapLayer.attributionUrl: src/core/qgsmaplayer.h#L425 -QgsMapLayer.autoRefreshInterval: src/core/qgsmaplayer.h#L1614 -QgsMapLayer.autoRefreshIntervalChanged: src/core/qgsmaplayer.h#L2058 -QgsMapLayer.autoRefreshMode: src/core/qgsmaplayer.h#L1606 -QgsMapLayer.beforeResolveReferences: src/core/qgsmaplayer.h#L1916 +QgsMapLayer.autoRefreshInterval: src/core/qgsmaplayer.h#L1617 +QgsMapLayer.autoRefreshIntervalChanged: src/core/qgsmaplayer.h#L2061 +QgsMapLayer.autoRefreshMode: src/core/qgsmaplayer.h#L1609 +QgsMapLayer.beforeResolveReferences: src/core/qgsmaplayer.h#L1919 QgsMapLayer.blendMode: src/core/qgsmaplayer.h#L515 -QgsMapLayer.blendModeChanged: src/core/qgsmaplayer.h#L1989 +QgsMapLayer.blendModeChanged: src/core/qgsmaplayer.h#L1992 QgsMapLayer.clone: src/core/qgsmaplayer.h#L213 -QgsMapLayer.clone: src/core/qgsmaplayer.h#L2165 -QgsMapLayer.configChanged: src/core/qgsmaplayer.h#L2040 +QgsMapLayer.clone: src/core/qgsmaplayer.h#L2168 +QgsMapLayer.configChanged: src/core/qgsmaplayer.h#L2043 QgsMapLayer.createMapRenderer: src/core/qgsmaplayer.h#L548 -QgsMapLayer.crs3D: src/core/qgsmaplayer.h#L1030 -QgsMapLayer.crs3DChanged: src/core/qgsmaplayer.h#L1955 -QgsMapLayer.crs: src/core/qgsmaplayer.h#L990 -QgsMapLayer.crsChanged: src/core/qgsmaplayer.h#L1944 -QgsMapLayer.customProperty: src/core/qgsmaplayer.h#L717 -QgsMapLayer.customPropertyChanged: src/core/qgsmaplayer.h#L2103 -QgsMapLayer.customPropertyKeys: src/core/qgsmaplayer.h#L704 -QgsMapLayer.dataChanged: src/core/qgsmaplayer.h#L1986 +QgsMapLayer.crs3D: src/core/qgsmaplayer.h#L1033 +QgsMapLayer.crs3DChanged: src/core/qgsmaplayer.h#L1958 +QgsMapLayer.crs: src/core/qgsmaplayer.h#L993 +QgsMapLayer.crsChanged: src/core/qgsmaplayer.h#L1947 +QgsMapLayer.customProperty: src/core/qgsmaplayer.h#L720 +QgsMapLayer.customPropertyChanged: src/core/qgsmaplayer.h#L2106 +QgsMapLayer.customPropertyKeys: src/core/qgsmaplayer.h#L707 +QgsMapLayer.dataChanged: src/core/qgsmaplayer.h#L1989 QgsMapLayer.dataProvider: src/core/qgsmaplayer.h#L301 -QgsMapLayer.dataSourceChanged: src/core/qgsmaplayer.h#L2082 +QgsMapLayer.dataSourceChanged: src/core/qgsmaplayer.h#L2085 QgsMapLayer.dataUrl: src/core/qgsmaplayer.h#L383 QgsMapLayer.dataUrlFormat: src/core/qgsmaplayer.h#L397 -QgsMapLayer.decodedSource: src/core/qgsmaplayer.h#L2216 -QgsMapLayer.deleteStyleFromDatabase: src/core/qgsmaplayer.h#L754 -QgsMapLayer.dependenciesChanged: src/core/qgsmaplayer.h#L2045 -QgsMapLayer.editingStarted: src/core/qgsmaplayer.h#L2109 -QgsMapLayer.editingStopped: src/core/qgsmaplayer.h#L2115 -QgsMapLayer.elevationProperties: src/core/qgsmaplayer.h#L1741 -QgsMapLayer.emitStyleChanged: src/core/qgsmaplayer.h#L1860 -QgsMapLayer.encodedSource: src/core/qgsmaplayer.h#L2202 -QgsMapLayer.error: src/core/qgsmaplayer.h#L977 -QgsMapLayer.exportNamedMetadata: src/core/qgsmaplayer.h#L1092 -QgsMapLayer.exportNamedStyle: src/core/qgsmaplayer.h#L1240 -QgsMapLayer.exportSldStyle: src/core/qgsmaplayer.h#L1251 -QgsMapLayer.exportSldStyleV2: src/core/qgsmaplayer.h#L1261 +QgsMapLayer.decodedSource: src/core/qgsmaplayer.h#L2219 +QgsMapLayer.deleteStyleFromDatabase: src/core/qgsmaplayer.h#L757 +QgsMapLayer.dependenciesChanged: src/core/qgsmaplayer.h#L2048 +QgsMapLayer.editingStarted: src/core/qgsmaplayer.h#L2112 +QgsMapLayer.editingStopped: src/core/qgsmaplayer.h#L2118 +QgsMapLayer.elevationProperties: src/core/qgsmaplayer.h#L1744 +QgsMapLayer.emitStyleChanged: src/core/qgsmaplayer.h#L1863 +QgsMapLayer.encodedSource: src/core/qgsmaplayer.h#L2205 +QgsMapLayer.error: src/core/qgsmaplayer.h#L980 +QgsMapLayer.exportNamedMetadata: src/core/qgsmaplayer.h#L1095 +QgsMapLayer.exportNamedStyle: src/core/qgsmaplayer.h#L1243 +QgsMapLayer.exportSldStyle: src/core/qgsmaplayer.h#L1254 +QgsMapLayer.exportSldStyleV2: src/core/qgsmaplayer.h#L1264 QgsMapLayer.extensionPropertyType: src/core/qgsmaplayer.h#L259 QgsMapLayer.extent3D: src/core/qgsmaplayer.h#L557 QgsMapLayer.extent: src/core/qgsmaplayer.h#L551 QgsMapLayer.flags: src/core/qgsmaplayer.h#L230 -QgsMapLayer.flagsChanged: src/core/qgsmaplayer.h#L2073 -QgsMapLayer.formatLayerName: src/core/qgsmaplayer.h#L1077 -QgsMapLayer.generateId: src/core/qgsmaplayer.h#L1709 -QgsMapLayer.getStyleFromDatabase: src/core/qgsmaplayer.h#L746 -QgsMapLayer.hasAutoRefreshEnabled: src/core/qgsmaplayer.h#L1598 -QgsMapLayer.hasDependencyCycle: src/core/qgsmaplayer.h#L2293 -QgsMapLayer.hasMapTips: src/core/qgsmaplayer.h#L1763 -QgsMapLayer.hasScaleBasedVisibility: src/core/qgsmaplayer.h#L1590 -QgsMapLayer.htmlMetadata: src/core/qgsmaplayer.h#L1661 +QgsMapLayer.flagsChanged: src/core/qgsmaplayer.h#L2076 +QgsMapLayer.formatLayerName: src/core/qgsmaplayer.h#L1080 +QgsMapLayer.generateId: src/core/qgsmaplayer.h#L1712 +QgsMapLayer.getStyleFromDatabase: src/core/qgsmaplayer.h#L749 +QgsMapLayer.hasAutoRefreshEnabled: src/core/qgsmaplayer.h#L1601 +QgsMapLayer.hasDependencyCycle: src/core/qgsmaplayer.h#L2296 +QgsMapLayer.hasMapTips: src/core/qgsmaplayer.h#L1766 +QgsMapLayer.hasScaleBasedVisibility: src/core/qgsmaplayer.h#L1593 +QgsMapLayer.htmlMetadata: src/core/qgsmaplayer.h#L1664 QgsMapLayer.id: src/core/qgsmaplayer.h#L267 -QgsMapLayer.idChanged: src/core/qgsmaplayer.h#L1929 -QgsMapLayer.importNamedMetadata: src/core/qgsmaplayer.h#L1165 -QgsMapLayer.importNamedStyle: src/core/qgsmaplayer.h#L1229 -QgsMapLayer.invalidateWgs84Extent: src/core/qgsmaplayer.h#L2267 -QgsMapLayer.isEditable: src/core/qgsmaplayer.h#L620 -QgsMapLayer.isInScaleRange: src/core/qgsmaplayer.h#L1556 -QgsMapLayer.isModified: src/core/qgsmaplayer.h#L627 -QgsMapLayer.isRefreshOnNotifyEnabled: src/core/qgsmaplayer.h#L1684 -QgsMapLayer.isSpatial: src/core/qgsmaplayer.h#L632 -QgsMapLayer.isTemporary: src/core/qgsmaplayer.h#L643 +QgsMapLayer.idChanged: src/core/qgsmaplayer.h#L1932 +QgsMapLayer.importNamedMetadata: src/core/qgsmaplayer.h#L1168 +QgsMapLayer.importNamedStyle: src/core/qgsmaplayer.h#L1232 +QgsMapLayer.invalidateWgs84Extent: src/core/qgsmaplayer.h#L2270 +QgsMapLayer.isEditable: src/core/qgsmaplayer.h#L623 +QgsMapLayer.isInScaleRange: src/core/qgsmaplayer.h#L1559 +QgsMapLayer.isModified: src/core/qgsmaplayer.h#L630 +QgsMapLayer.isRefreshOnNotifyEnabled: src/core/qgsmaplayer.h#L1687 +QgsMapLayer.isSpatial: src/core/qgsmaplayer.h#L635 +QgsMapLayer.isTemporary: src/core/qgsmaplayer.h#L646 QgsMapLayer.isValid: src/core/qgsmaplayer.h#L574 -QgsMapLayer.isValidChanged: src/core/qgsmaplayer.h#L2096 +QgsMapLayer.isValidChanged: src/core/qgsmaplayer.h#L2099 QgsMapLayer.keywordList: src/core/qgsmaplayer.h#L369 -QgsMapLayer.layerModified: src/core/qgsmaplayer.h#L2121 -QgsMapLayer.legend: src/core/qgsmaplayer.h#L1531 -QgsMapLayer.legendChanged: src/core/qgsmaplayer.h#L2022 -QgsMapLayer.legendPlaceholderImage: src/core/qgsmaplayer.h#L1748 -QgsMapLayer.legendUrl: src/core/qgsmaplayer.h#L1510 -QgsMapLayer.legendUrlFormat: src/core/qgsmaplayer.h#L1520 -QgsMapLayer.listStylesInDatabase: src/core/qgsmaplayer.h#L740 -QgsMapLayer.loadDefaultMetadata: src/core/qgsmaplayer.h#L1148 -QgsMapLayer.loadDefaultStyle: src/core/qgsmaplayer.h#L1189 -QgsMapLayer.loadNamedMetadata: src/core/qgsmaplayer.h#L1135 -QgsMapLayer.loadNamedMetadataFromDatabase: src/core/qgsmaplayer.h#L1157 -QgsMapLayer.loadNamedStyle: src/core/qgsmaplayer.h#L1210 -QgsMapLayer.loadNamedStyle: src/core/qgsmaplayer.h#L791 -QgsMapLayer.loadNamedStyleFromDatabase: src/core/qgsmaplayer.h#L1219 -QgsMapLayer.loadSldStyle: src/core/qgsmaplayer.h#L1337 -QgsMapLayer.mapTipTemplate: src/core/qgsmaplayer.h#L1772 -QgsMapLayer.mapTipTemplateChanged: src/core/qgsmaplayer.h#L2128 -QgsMapLayer.mapTipsEnabled: src/core/qgsmaplayer.h#L1795 -QgsMapLayer.mapTipsEnabledChanged: src/core/qgsmaplayer.h#L2136 -QgsMapLayer.maximumScale: src/core/qgsmaplayer.h#L1580 -QgsMapLayer.metadataChanged: src/core/qgsmaplayer.h#L2065 -QgsMapLayer.metadataUri: src/core/qgsmaplayer.h#L1085 +QgsMapLayer.layerModified: src/core/qgsmaplayer.h#L2124 +QgsMapLayer.legend: src/core/qgsmaplayer.h#L1534 +QgsMapLayer.legendChanged: src/core/qgsmaplayer.h#L2025 +QgsMapLayer.legendPlaceholderImage: src/core/qgsmaplayer.h#L1751 +QgsMapLayer.legendUrl: src/core/qgsmaplayer.h#L1513 +QgsMapLayer.legendUrlFormat: src/core/qgsmaplayer.h#L1523 +QgsMapLayer.listStylesInDatabase: src/core/qgsmaplayer.h#L743 +QgsMapLayer.loadDefaultMetadata: src/core/qgsmaplayer.h#L1151 +QgsMapLayer.loadDefaultStyle: src/core/qgsmaplayer.h#L1192 +QgsMapLayer.loadNamedMetadata: src/core/qgsmaplayer.h#L1138 +QgsMapLayer.loadNamedMetadataFromDatabase: src/core/qgsmaplayer.h#L1160 +QgsMapLayer.loadNamedStyle: src/core/qgsmaplayer.h#L1213 +QgsMapLayer.loadNamedStyle: src/core/qgsmaplayer.h#L794 +QgsMapLayer.loadNamedStyleFromDatabase: src/core/qgsmaplayer.h#L1222 +QgsMapLayer.loadSldStyle: src/core/qgsmaplayer.h#L1340 +QgsMapLayer.mapTipTemplate: src/core/qgsmaplayer.h#L1775 +QgsMapLayer.mapTipTemplateChanged: src/core/qgsmaplayer.h#L2131 +QgsMapLayer.mapTipsEnabled: src/core/qgsmaplayer.h#L1798 +QgsMapLayer.mapTipsEnabledChanged: src/core/qgsmaplayer.h#L2139 +QgsMapLayer.maximumScale: src/core/qgsmaplayer.h#L1583 +QgsMapLayer.metadataChanged: src/core/qgsmaplayer.h#L2068 +QgsMapLayer.metadataUri: src/core/qgsmaplayer.h#L1088 QgsMapLayer.metadataUrl: src/core/qgsmaplayer.h#L460 QgsMapLayer.metadataUrlFormat: src/core/qgsmaplayer.h#L502 QgsMapLayer.metadataUrlType: src/core/qgsmaplayer.h#L481 -QgsMapLayer.minimumScale: src/core/qgsmaplayer.h#L1568 +QgsMapLayer.minimumScale: src/core/qgsmaplayer.h#L1571 QgsMapLayer.name: src/core/qgsmaplayer.h#L296 -QgsMapLayer.nameChanged: src/core/qgsmaplayer.h#L1934 +QgsMapLayer.nameChanged: src/core/qgsmaplayer.h#L1937 QgsMapLayer.opacity: src/core/qgsmaplayer.h#L535 -QgsMapLayer.opacityChanged: src/core/qgsmaplayer.h#L1999 -QgsMapLayer.originalXmlProperties: src/core/qgsmaplayer.h#L1694 -QgsMapLayer.project: src/core/qgsmaplayer.h#L1906 +QgsMapLayer.opacityChanged: src/core/qgsmaplayer.h#L2002 +QgsMapLayer.originalXmlProperties: src/core/qgsmaplayer.h#L1697 +QgsMapLayer.project: src/core/qgsmaplayer.h#L1909 QgsMapLayer.properties: src/core/qgsmaplayer.h#L253 QgsMapLayer.providerMetadata: src/core/qgsmaplayer.h#L313 -QgsMapLayer.providerReadFlags: src/core/qgsmaplayer.h#L1804 -QgsMapLayer.providerType: src/core/qgsmaplayer.h#L1492 -QgsMapLayer.publicSource: src/core/qgsmaplayer.h#L583 -QgsMapLayer.readCommonStyle: src/core/qgsmaplayer.h#L2243 -QgsMapLayer.readCustomProperties: src/core/qgsmaplayer.h#L2223 -QgsMapLayer.readLayerXml: src/core/qgsmaplayer.h#L675 +QgsMapLayer.providerReadFlags: src/core/qgsmaplayer.h#L1807 +QgsMapLayer.providerType: src/core/qgsmaplayer.h#L1495 +QgsMapLayer.publicSource: src/core/qgsmaplayer.h#L586 +QgsMapLayer.readCommonStyle: src/core/qgsmaplayer.h#L2246 +QgsMapLayer.readCustomProperties: src/core/qgsmaplayer.h#L2226 +QgsMapLayer.readLayerXml: src/core/qgsmaplayer.h#L678 QgsMapLayer.readOnly: src/core/qgsmaplayer.h#L538 -QgsMapLayer.readSld: src/core/qgsmaplayer.h#L1340 -QgsMapLayer.readStyle: src/core/qgsmaplayer.h#L1364 -QgsMapLayer.readStyleManager: src/core/qgsmaplayer.h#L2229 -QgsMapLayer.readSymbology: src/core/qgsmaplayer.h#L1352 -QgsMapLayer.readXml: src/core/qgsmaplayer.h#L2183 -QgsMapLayer.recalculateExtents: src/core/qgsmaplayer.h#L1983 -QgsMapLayer.refreshOnNotifyMessage: src/core/qgsmaplayer.h#L1678 +QgsMapLayer.readSld: src/core/qgsmaplayer.h#L1343 +QgsMapLayer.readStyle: src/core/qgsmaplayer.h#L1367 +QgsMapLayer.readStyleManager: src/core/qgsmaplayer.h#L2232 +QgsMapLayer.readSymbology: src/core/qgsmaplayer.h#L1355 +QgsMapLayer.readXml: src/core/qgsmaplayer.h#L2186 +QgsMapLayer.recalculateExtents: src/core/qgsmaplayer.h#L1986 +QgsMapLayer.refreshOnNotifyMessage: src/core/qgsmaplayer.h#L1681 QgsMapLayer.reload: src/core/qgsmaplayer.h#L543 -QgsMapLayer.removeCustomProperty: src/core/qgsmaplayer.h#L970 -QgsMapLayer.renderer3D: src/core/qgsmaplayer.h#L1546 -QgsMapLayer.renderer3DChanged: src/core/qgsmaplayer.h#L2027 -QgsMapLayer.rendererChanged: src/core/qgsmaplayer.h#L2005 -QgsMapLayer.repaintRequested: src/core/qgsmaplayer.h#L1980 -QgsMapLayer.request3DUpdate: src/core/qgsmaplayer.h#L2034 -QgsMapLayer.resolveReferences: src/core/qgsmaplayer.h#L698 -QgsMapLayer.saveDefaultMetadata: src/core/qgsmaplayer.h#L1102 -QgsMapLayer.saveDefaultStyle: src/core/qgsmaplayer.h#L1274 -QgsMapLayer.saveDefaultStyle: src/core/qgsmaplayer.h#L1287 -QgsMapLayer.saveNamedMetadata: src/core/qgsmaplayer.h#L1117 -QgsMapLayer.saveNamedStyle: src/core/qgsmaplayer.h#L1304 -QgsMapLayer.saveSldStyle: src/core/qgsmaplayer.h#L1315 -QgsMapLayer.saveSldStyleV2: src/core/qgsmaplayer.h#L1327 -QgsMapLayer.saveStyleToDatabase: src/core/qgsmaplayer.h#L772 -QgsMapLayer.selectionProperties: src/core/qgsmaplayer.h#L1727 +QgsMapLayer.removeCustomProperty: src/core/qgsmaplayer.h#L973 +QgsMapLayer.renderer3D: src/core/qgsmaplayer.h#L1549 +QgsMapLayer.renderer3DChanged: src/core/qgsmaplayer.h#L2030 +QgsMapLayer.rendererChanged: src/core/qgsmaplayer.h#L2008 +QgsMapLayer.repaintRequested: src/core/qgsmaplayer.h#L1983 +QgsMapLayer.request3DUpdate: src/core/qgsmaplayer.h#L2037 +QgsMapLayer.resolveReferences: src/core/qgsmaplayer.h#L701 +QgsMapLayer.saveDefaultMetadata: src/core/qgsmaplayer.h#L1105 +QgsMapLayer.saveDefaultStyle: src/core/qgsmaplayer.h#L1277 +QgsMapLayer.saveDefaultStyle: src/core/qgsmaplayer.h#L1290 +QgsMapLayer.saveNamedMetadata: src/core/qgsmaplayer.h#L1120 +QgsMapLayer.saveNamedStyle: src/core/qgsmaplayer.h#L1307 +QgsMapLayer.saveSldStyle: src/core/qgsmaplayer.h#L1318 +QgsMapLayer.saveSldStyleV2: src/core/qgsmaplayer.h#L1330 +QgsMapLayer.saveStyleToDatabase: src/core/qgsmaplayer.h#L775 +QgsMapLayer.selectionProperties: src/core/qgsmaplayer.h#L1730 QgsMapLayer.serverProperties: src/core/qgsmaplayer.h#L434 QgsMapLayer.setAbstract: src/core/qgsmaplayer.h#L348 QgsMapLayer.setAttribution: src/core/qgsmaplayer.h#L404 QgsMapLayer.setAttributionUrl: src/core/qgsmaplayer.h#L418 -QgsMapLayer.setAutoRefreshEnabled: src/core/qgsmaplayer.h#L1634 -QgsMapLayer.setAutoRefreshInterval: src/core/qgsmaplayer.h#L1626 -QgsMapLayer.setAutoRefreshMode: src/core/qgsmaplayer.h#L1642 +QgsMapLayer.setAutoRefreshEnabled: src/core/qgsmaplayer.h#L1637 +QgsMapLayer.setAutoRefreshInterval: src/core/qgsmaplayer.h#L1629 +QgsMapLayer.setAutoRefreshMode: src/core/qgsmaplayer.h#L1645 QgsMapLayer.setBlendMode: src/core/qgsmaplayer.h#L509 -QgsMapLayer.setCrs: src/core/qgsmaplayer.h#L1042 -QgsMapLayer.setCustomProperties: src/core/qgsmaplayer.h#L722 -QgsMapLayer.setCustomProperty: src/core/qgsmaplayer.h#L711 -QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1425 -QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1456 -QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1487 +QgsMapLayer.setCrs: src/core/qgsmaplayer.h#L1045 +QgsMapLayer.setCustomProperties: src/core/qgsmaplayer.h#L725 +QgsMapLayer.setCustomProperty: src/core/qgsmaplayer.h#L714 +QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1428 +QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1459 +QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1490 QgsMapLayer.setDataUrl: src/core/qgsmaplayer.h#L376 QgsMapLayer.setDataUrlFormat: src/core/qgsmaplayer.h#L390 -QgsMapLayer.setDependencies: src/core/qgsmaplayer.h#L1869 -QgsMapLayer.setError: src/core/qgsmaplayer.h#L2259 -QgsMapLayer.setExtent3D: src/core/qgsmaplayer.h#L2174 -QgsMapLayer.setExtent: src/core/qgsmaplayer.h#L2168 +QgsMapLayer.setDependencies: src/core/qgsmaplayer.h#L1872 +QgsMapLayer.setError: src/core/qgsmaplayer.h#L2262 +QgsMapLayer.setExtent3D: src/core/qgsmaplayer.h#L2177 +QgsMapLayer.setExtent: src/core/qgsmaplayer.h#L2171 QgsMapLayer.setFlags: src/core/qgsmaplayer.h#L242 QgsMapLayer.setId: src/core/qgsmaplayer.h#L284 QgsMapLayer.setKeywordList: src/core/qgsmaplayer.h#L362 -QgsMapLayer.setLayerOrder: src/core/qgsmaplayer.h#L602 -QgsMapLayer.setLegend: src/core/qgsmaplayer.h#L1526 -QgsMapLayer.setLegendPlaceholderImage: src/core/qgsmaplayer.h#L1755 -QgsMapLayer.setLegendUrl: src/core/qgsmaplayer.h#L1505 -QgsMapLayer.setLegendUrlFormat: src/core/qgsmaplayer.h#L1515 -QgsMapLayer.setMapTipTemplate: src/core/qgsmaplayer.h#L1781 -QgsMapLayer.setMapTipsEnabled: src/core/qgsmaplayer.h#L1789 -QgsMapLayer.setMaximumScale: src/core/qgsmaplayer.h#L1828 -QgsMapLayer.setMetadata: src/core/qgsmaplayer.h#L1656 +QgsMapLayer.setLayerOrder: src/core/qgsmaplayer.h#L605 +QgsMapLayer.setLegend: src/core/qgsmaplayer.h#L1529 +QgsMapLayer.setLegendPlaceholderImage: src/core/qgsmaplayer.h#L1758 +QgsMapLayer.setLegendUrl: src/core/qgsmaplayer.h#L1508 +QgsMapLayer.setLegendUrlFormat: src/core/qgsmaplayer.h#L1518 +QgsMapLayer.setMapTipTemplate: src/core/qgsmaplayer.h#L1784 +QgsMapLayer.setMapTipsEnabled: src/core/qgsmaplayer.h#L1792 +QgsMapLayer.setMaximumScale: src/core/qgsmaplayer.h#L1831 +QgsMapLayer.setMetadata: src/core/qgsmaplayer.h#L1659 QgsMapLayer.setMetadataUrl: src/core/qgsmaplayer.h#L449 QgsMapLayer.setMetadataUrlFormat: src/core/qgsmaplayer.h#L491 QgsMapLayer.setMetadataUrlType: src/core/qgsmaplayer.h#L470 -QgsMapLayer.setMinimumScale: src/core/qgsmaplayer.h#L1817 +QgsMapLayer.setMinimumScale: src/core/qgsmaplayer.h#L1820 QgsMapLayer.setName: src/core/qgsmaplayer.h#L290 QgsMapLayer.setOpacity: src/core/qgsmaplayer.h#L525 -QgsMapLayer.setOriginalXmlProperties: src/core/qgsmaplayer.h#L1703 -QgsMapLayer.setProviderType: src/core/qgsmaplayer.h#L2247 -QgsMapLayer.setRefreshOnNofifyMessage: src/core/qgsmaplayer.h#L1883 -QgsMapLayer.setRefreshOnNotifyEnabled: src/core/qgsmaplayer.h#L1875 -QgsMapLayer.setRenderer3D: src/core/qgsmaplayer.h#L1541 -QgsMapLayer.setScaleBasedVisibility: src/core/qgsmaplayer.h#L1837 +QgsMapLayer.setOriginalXmlProperties: src/core/qgsmaplayer.h#L1706 +QgsMapLayer.setProviderType: src/core/qgsmaplayer.h#L2250 +QgsMapLayer.setRefreshOnNofifyMessage: src/core/qgsmaplayer.h#L1886 +QgsMapLayer.setRefreshOnNotifyEnabled: src/core/qgsmaplayer.h#L1878 +QgsMapLayer.setRenderer3D: src/core/qgsmaplayer.h#L1544 +QgsMapLayer.setScaleBasedVisibility: src/core/qgsmaplayer.h#L1840 QgsMapLayer.setShortName: src/core/qgsmaplayer.h#L320 -QgsMapLayer.setSubLayerVisibility: src/core/qgsmaplayer.h#L609 +QgsMapLayer.setSubLayerVisibility: src/core/qgsmaplayer.h#L612 QgsMapLayer.setTitle: src/core/qgsmaplayer.h#L334 -QgsMapLayer.setTransformContext: src/core/qgsmaplayer.h#L1890 -QgsMapLayer.setValid: src/core/qgsmaplayer.h#L2177 -QgsMapLayer.setVerticalCrs: src/core/qgsmaplayer.h#L1063 +QgsMapLayer.setTransformContext: src/core/qgsmaplayer.h#L1893 +QgsMapLayer.setValid: src/core/qgsmaplayer.h#L2180 +QgsMapLayer.setVerticalCrs: src/core/qgsmaplayer.h#L1066 QgsMapLayer.shortName: src/core/qgsmaplayer.h#L327 -QgsMapLayer.source: src/core/qgsmaplayer.h#L590 -QgsMapLayer.statusChanged: src/core/qgsmaplayer.h#L1919 -QgsMapLayer.styleChanged: src/core/qgsmaplayer.h#L2017 -QgsMapLayer.styleLoaded: src/core/qgsmaplayer.h#L2089 -QgsMapLayer.styleManager: src/core/qgsmaplayer.h#L1536 -QgsMapLayer.styleURI: src/core/qgsmaplayer.h#L1175 -QgsMapLayer.subLayers: src/core/qgsmaplayer.h#L596 -QgsMapLayer.supportsEditing: src/core/qgsmaplayer.h#L617 -QgsMapLayer.temporalProperties: src/core/qgsmaplayer.h#L1734 -QgsMapLayer.timestamp: src/core/qgsmaplayer.h#L1664 +QgsMapLayer.source: src/core/qgsmaplayer.h#L593 +QgsMapLayer.statusChanged: src/core/qgsmaplayer.h#L1922 +QgsMapLayer.styleChanged: src/core/qgsmaplayer.h#L2020 +QgsMapLayer.styleLoaded: src/core/qgsmaplayer.h#L2092 +QgsMapLayer.styleManager: src/core/qgsmaplayer.h#L1539 +QgsMapLayer.styleURI: src/core/qgsmaplayer.h#L1178 +QgsMapLayer.subLayers: src/core/qgsmaplayer.h#L599 +QgsMapLayer.supportsEditing: src/core/qgsmaplayer.h#L620 +QgsMapLayer.temporalProperties: src/core/qgsmaplayer.h#L1737 +QgsMapLayer.timestamp: src/core/qgsmaplayer.h#L1667 QgsMapLayer.title: src/core/qgsmaplayer.h#L341 -QgsMapLayer.transformContext: src/core/qgsmaplayer.h#L1070 -QgsMapLayer.trigger3DUpdate: src/core/qgsmaplayer.h#L1855 -QgsMapLayer.triggerRepaint: src/core/qgsmaplayer.h#L1847 +QgsMapLayer.transformContext: src/core/qgsmaplayer.h#L1073 +QgsMapLayer.trigger3DUpdate: src/core/qgsmaplayer.h#L1858 +QgsMapLayer.triggerRepaint: src/core/qgsmaplayer.h#L1850 QgsMapLayer.type: src/core/qgsmaplayer.h#L218 -QgsMapLayer.undoStack: src/core/qgsmaplayer.h#L1495 -QgsMapLayer.undoStackStyles: src/core/qgsmaplayer.h#L1500 -QgsMapLayer.verticalCrs: src/core/qgsmaplayer.h#L1010 -QgsMapLayer.verticalCrsChanged: src/core/qgsmaplayer.h#L1972 +QgsMapLayer.undoStack: src/core/qgsmaplayer.h#L1498 +QgsMapLayer.undoStackStyles: src/core/qgsmaplayer.h#L1503 +QgsMapLayer.verticalCrs: src/core/qgsmaplayer.h#L1013 +QgsMapLayer.verticalCrsChanged: src/core/qgsmaplayer.h#L1975 QgsMapLayer.wgs84Extent: src/core/qgsmaplayer.h#L567 -QgsMapLayer.willBeDeleted: src/core/qgsmaplayer.h#L2052 -QgsMapLayer.writeCommonStyle: src/core/qgsmaplayer.h#L2236 -QgsMapLayer.writeCustomProperties: src/core/qgsmaplayer.h#L2226 -QgsMapLayer.writeLayerXml: src/core/qgsmaplayer.h#L693 -QgsMapLayer.writeStyle: src/core/qgsmaplayer.h#L1391 -QgsMapLayer.writeStyleManager: src/core/qgsmaplayer.h#L2231 -QgsMapLayer.writeSymbology: src/core/qgsmaplayer.h#L1377 -QgsMapLayer.writeXml: src/core/qgsmaplayer.h#L2189 +QgsMapLayer.willBeDeleted: src/core/qgsmaplayer.h#L2055 +QgsMapLayer.writeCommonStyle: src/core/qgsmaplayer.h#L2239 +QgsMapLayer.writeCustomProperties: src/core/qgsmaplayer.h#L2229 +QgsMapLayer.writeLayerXml: src/core/qgsmaplayer.h#L696 +QgsMapLayer.writeStyle: src/core/qgsmaplayer.h#L1394 +QgsMapLayer.writeStyleManager: src/core/qgsmaplayer.h#L2234 +QgsMapLayer.writeSymbology: src/core/qgsmaplayer.h#L1380 +QgsMapLayer.writeXml: src/core/qgsmaplayer.h#L2192 QgsMapLayer: src/core/qgsmaplayer.h#L75 QgsMapLayerDependency.__hash__: src/core/qgsmaplayerdependency.h#L78 QgsMapLayerDependency.layerId: src/core/qgsmaplayerdependency.h#L67 diff --git a/python/core/class_map.yaml b/python/core/class_map.yaml index c5eb4c922425c..5ecd30fe2d19e 100644 --- a/python/core/class_map.yaml +++ b/python/core/class_map.yaml @@ -8863,218 +8863,218 @@ QgsMapInfoSymbolConverter.convertFillSymbol: src/core/symbology/qgsmapinfosymbol QgsMapInfoSymbolConverter.convertLineSymbol: src/core/symbology/qgsmapinfosymbolconverter.h#L75 QgsMapInfoSymbolConverter.convertMarkerSymbol: src/core/symbology/qgsmapinfosymbolconverter.h#L91 QgsMapInfoSymbolConverter: src/core/symbology/qgsmapinfosymbolconverter.h#L66 -QgsMapLayer.__repr__: src/core/qgsmaplayer.h#L1893 +QgsMapLayer.__repr__: src/core/qgsmaplayer.h#L1896 QgsMapLayer.abstract: src/core/qgsmaplayer.h#L355 -QgsMapLayer.accept: src/core/qgsmaplayer.h#L1720 -QgsMapLayer.appendError: src/core/qgsmaplayer.h#L2257 +QgsMapLayer.accept: src/core/qgsmaplayer.h#L1723 +QgsMapLayer.appendError: src/core/qgsmaplayer.h#L2260 QgsMapLayer.attribution: src/core/qgsmaplayer.h#L411 QgsMapLayer.attributionUrl: src/core/qgsmaplayer.h#L425 -QgsMapLayer.autoRefreshInterval: src/core/qgsmaplayer.h#L1614 -QgsMapLayer.autoRefreshIntervalChanged: src/core/qgsmaplayer.h#L2058 -QgsMapLayer.autoRefreshMode: src/core/qgsmaplayer.h#L1606 -QgsMapLayer.beforeResolveReferences: src/core/qgsmaplayer.h#L1916 +QgsMapLayer.autoRefreshInterval: src/core/qgsmaplayer.h#L1617 +QgsMapLayer.autoRefreshIntervalChanged: src/core/qgsmaplayer.h#L2061 +QgsMapLayer.autoRefreshMode: src/core/qgsmaplayer.h#L1609 +QgsMapLayer.beforeResolveReferences: src/core/qgsmaplayer.h#L1919 QgsMapLayer.blendMode: src/core/qgsmaplayer.h#L515 -QgsMapLayer.blendModeChanged: src/core/qgsmaplayer.h#L1989 +QgsMapLayer.blendModeChanged: src/core/qgsmaplayer.h#L1992 QgsMapLayer.clone: src/core/qgsmaplayer.h#L213 -QgsMapLayer.clone: src/core/qgsmaplayer.h#L2165 -QgsMapLayer.configChanged: src/core/qgsmaplayer.h#L2040 +QgsMapLayer.clone: src/core/qgsmaplayer.h#L2168 +QgsMapLayer.configChanged: src/core/qgsmaplayer.h#L2043 QgsMapLayer.createMapRenderer: src/core/qgsmaplayer.h#L548 -QgsMapLayer.crs3D: src/core/qgsmaplayer.h#L1030 -QgsMapLayer.crs3DChanged: src/core/qgsmaplayer.h#L1955 -QgsMapLayer.crs: src/core/qgsmaplayer.h#L990 -QgsMapLayer.crsChanged: src/core/qgsmaplayer.h#L1944 -QgsMapLayer.customProperty: src/core/qgsmaplayer.h#L717 -QgsMapLayer.customPropertyChanged: src/core/qgsmaplayer.h#L2103 -QgsMapLayer.customPropertyKeys: src/core/qgsmaplayer.h#L704 -QgsMapLayer.dataChanged: src/core/qgsmaplayer.h#L1986 +QgsMapLayer.crs3D: src/core/qgsmaplayer.h#L1033 +QgsMapLayer.crs3DChanged: src/core/qgsmaplayer.h#L1958 +QgsMapLayer.crs: src/core/qgsmaplayer.h#L993 +QgsMapLayer.crsChanged: src/core/qgsmaplayer.h#L1947 +QgsMapLayer.customProperty: src/core/qgsmaplayer.h#L720 +QgsMapLayer.customPropertyChanged: src/core/qgsmaplayer.h#L2106 +QgsMapLayer.customPropertyKeys: src/core/qgsmaplayer.h#L707 +QgsMapLayer.dataChanged: src/core/qgsmaplayer.h#L1989 QgsMapLayer.dataProvider: src/core/qgsmaplayer.h#L301 -QgsMapLayer.dataSourceChanged: src/core/qgsmaplayer.h#L2082 +QgsMapLayer.dataSourceChanged: src/core/qgsmaplayer.h#L2085 QgsMapLayer.dataUrl: src/core/qgsmaplayer.h#L383 QgsMapLayer.dataUrlFormat: src/core/qgsmaplayer.h#L397 -QgsMapLayer.decodedSource: src/core/qgsmaplayer.h#L2216 -QgsMapLayer.deleteStyleFromDatabase: src/core/qgsmaplayer.h#L754 -QgsMapLayer.dependenciesChanged: src/core/qgsmaplayer.h#L2045 -QgsMapLayer.editingStarted: src/core/qgsmaplayer.h#L2109 -QgsMapLayer.editingStopped: src/core/qgsmaplayer.h#L2115 -QgsMapLayer.elevationProperties: src/core/qgsmaplayer.h#L1741 -QgsMapLayer.emitStyleChanged: src/core/qgsmaplayer.h#L1860 -QgsMapLayer.encodedSource: src/core/qgsmaplayer.h#L2202 -QgsMapLayer.error: src/core/qgsmaplayer.h#L977 -QgsMapLayer.exportNamedMetadata: src/core/qgsmaplayer.h#L1092 -QgsMapLayer.exportNamedStyle: src/core/qgsmaplayer.h#L1240 -QgsMapLayer.exportSldStyle: src/core/qgsmaplayer.h#L1251 -QgsMapLayer.exportSldStyleV2: src/core/qgsmaplayer.h#L1261 +QgsMapLayer.decodedSource: src/core/qgsmaplayer.h#L2219 +QgsMapLayer.deleteStyleFromDatabase: src/core/qgsmaplayer.h#L757 +QgsMapLayer.dependenciesChanged: src/core/qgsmaplayer.h#L2048 +QgsMapLayer.editingStarted: src/core/qgsmaplayer.h#L2112 +QgsMapLayer.editingStopped: src/core/qgsmaplayer.h#L2118 +QgsMapLayer.elevationProperties: src/core/qgsmaplayer.h#L1744 +QgsMapLayer.emitStyleChanged: src/core/qgsmaplayer.h#L1863 +QgsMapLayer.encodedSource: src/core/qgsmaplayer.h#L2205 +QgsMapLayer.error: src/core/qgsmaplayer.h#L980 +QgsMapLayer.exportNamedMetadata: src/core/qgsmaplayer.h#L1095 +QgsMapLayer.exportNamedStyle: src/core/qgsmaplayer.h#L1243 +QgsMapLayer.exportSldStyle: src/core/qgsmaplayer.h#L1254 +QgsMapLayer.exportSldStyleV2: src/core/qgsmaplayer.h#L1264 QgsMapLayer.extensionPropertyType: src/core/qgsmaplayer.h#L259 QgsMapLayer.extent3D: src/core/qgsmaplayer.h#L557 QgsMapLayer.extent: src/core/qgsmaplayer.h#L551 QgsMapLayer.flags: src/core/qgsmaplayer.h#L230 -QgsMapLayer.flagsChanged: src/core/qgsmaplayer.h#L2073 -QgsMapLayer.formatLayerName: src/core/qgsmaplayer.h#L1077 -QgsMapLayer.generateId: src/core/qgsmaplayer.h#L1709 -QgsMapLayer.getStyleFromDatabase: src/core/qgsmaplayer.h#L746 -QgsMapLayer.hasAutoRefreshEnabled: src/core/qgsmaplayer.h#L1598 -QgsMapLayer.hasDependencyCycle: src/core/qgsmaplayer.h#L2293 -QgsMapLayer.hasMapTips: src/core/qgsmaplayer.h#L1763 -QgsMapLayer.hasScaleBasedVisibility: src/core/qgsmaplayer.h#L1590 -QgsMapLayer.htmlMetadata: src/core/qgsmaplayer.h#L1661 +QgsMapLayer.flagsChanged: src/core/qgsmaplayer.h#L2076 +QgsMapLayer.formatLayerName: src/core/qgsmaplayer.h#L1080 +QgsMapLayer.generateId: src/core/qgsmaplayer.h#L1712 +QgsMapLayer.getStyleFromDatabase: src/core/qgsmaplayer.h#L749 +QgsMapLayer.hasAutoRefreshEnabled: src/core/qgsmaplayer.h#L1601 +QgsMapLayer.hasDependencyCycle: src/core/qgsmaplayer.h#L2296 +QgsMapLayer.hasMapTips: src/core/qgsmaplayer.h#L1766 +QgsMapLayer.hasScaleBasedVisibility: src/core/qgsmaplayer.h#L1593 +QgsMapLayer.htmlMetadata: src/core/qgsmaplayer.h#L1664 QgsMapLayer.id: src/core/qgsmaplayer.h#L267 -QgsMapLayer.idChanged: src/core/qgsmaplayer.h#L1929 -QgsMapLayer.importNamedMetadata: src/core/qgsmaplayer.h#L1165 -QgsMapLayer.importNamedStyle: src/core/qgsmaplayer.h#L1229 -QgsMapLayer.invalidateWgs84Extent: src/core/qgsmaplayer.h#L2267 -QgsMapLayer.isEditable: src/core/qgsmaplayer.h#L620 -QgsMapLayer.isInScaleRange: src/core/qgsmaplayer.h#L1556 -QgsMapLayer.isModified: src/core/qgsmaplayer.h#L627 -QgsMapLayer.isRefreshOnNotifyEnabled: src/core/qgsmaplayer.h#L1684 -QgsMapLayer.isSpatial: src/core/qgsmaplayer.h#L632 -QgsMapLayer.isTemporary: src/core/qgsmaplayer.h#L643 +QgsMapLayer.idChanged: src/core/qgsmaplayer.h#L1932 +QgsMapLayer.importNamedMetadata: src/core/qgsmaplayer.h#L1168 +QgsMapLayer.importNamedStyle: src/core/qgsmaplayer.h#L1232 +QgsMapLayer.invalidateWgs84Extent: src/core/qgsmaplayer.h#L2270 +QgsMapLayer.isEditable: src/core/qgsmaplayer.h#L623 +QgsMapLayer.isInScaleRange: src/core/qgsmaplayer.h#L1559 +QgsMapLayer.isModified: src/core/qgsmaplayer.h#L630 +QgsMapLayer.isRefreshOnNotifyEnabled: src/core/qgsmaplayer.h#L1687 +QgsMapLayer.isSpatial: src/core/qgsmaplayer.h#L635 +QgsMapLayer.isTemporary: src/core/qgsmaplayer.h#L646 QgsMapLayer.isValid: src/core/qgsmaplayer.h#L574 -QgsMapLayer.isValidChanged: src/core/qgsmaplayer.h#L2096 +QgsMapLayer.isValidChanged: src/core/qgsmaplayer.h#L2099 QgsMapLayer.keywordList: src/core/qgsmaplayer.h#L369 -QgsMapLayer.layerModified: src/core/qgsmaplayer.h#L2121 -QgsMapLayer.legend: src/core/qgsmaplayer.h#L1531 -QgsMapLayer.legendChanged: src/core/qgsmaplayer.h#L2022 -QgsMapLayer.legendPlaceholderImage: src/core/qgsmaplayer.h#L1748 -QgsMapLayer.legendUrl: src/core/qgsmaplayer.h#L1510 -QgsMapLayer.legendUrlFormat: src/core/qgsmaplayer.h#L1520 -QgsMapLayer.listStylesInDatabase: src/core/qgsmaplayer.h#L740 -QgsMapLayer.loadDefaultMetadata: src/core/qgsmaplayer.h#L1148 -QgsMapLayer.loadDefaultStyle: src/core/qgsmaplayer.h#L1189 -QgsMapLayer.loadNamedMetadata: src/core/qgsmaplayer.h#L1135 -QgsMapLayer.loadNamedMetadataFromDatabase: src/core/qgsmaplayer.h#L1157 -QgsMapLayer.loadNamedStyle: src/core/qgsmaplayer.h#L1210 -QgsMapLayer.loadNamedStyle: src/core/qgsmaplayer.h#L791 -QgsMapLayer.loadNamedStyleFromDatabase: src/core/qgsmaplayer.h#L1219 -QgsMapLayer.loadSldStyle: src/core/qgsmaplayer.h#L1337 -QgsMapLayer.mapTipTemplate: src/core/qgsmaplayer.h#L1772 -QgsMapLayer.mapTipTemplateChanged: src/core/qgsmaplayer.h#L2128 -QgsMapLayer.mapTipsEnabled: src/core/qgsmaplayer.h#L1795 -QgsMapLayer.mapTipsEnabledChanged: src/core/qgsmaplayer.h#L2136 -QgsMapLayer.maximumScale: src/core/qgsmaplayer.h#L1580 -QgsMapLayer.metadataChanged: src/core/qgsmaplayer.h#L2065 -QgsMapLayer.metadataUri: src/core/qgsmaplayer.h#L1085 +QgsMapLayer.layerModified: src/core/qgsmaplayer.h#L2124 +QgsMapLayer.legend: src/core/qgsmaplayer.h#L1534 +QgsMapLayer.legendChanged: src/core/qgsmaplayer.h#L2025 +QgsMapLayer.legendPlaceholderImage: src/core/qgsmaplayer.h#L1751 +QgsMapLayer.legendUrl: src/core/qgsmaplayer.h#L1513 +QgsMapLayer.legendUrlFormat: src/core/qgsmaplayer.h#L1523 +QgsMapLayer.listStylesInDatabase: src/core/qgsmaplayer.h#L743 +QgsMapLayer.loadDefaultMetadata: src/core/qgsmaplayer.h#L1151 +QgsMapLayer.loadDefaultStyle: src/core/qgsmaplayer.h#L1192 +QgsMapLayer.loadNamedMetadata: src/core/qgsmaplayer.h#L1138 +QgsMapLayer.loadNamedMetadataFromDatabase: src/core/qgsmaplayer.h#L1160 +QgsMapLayer.loadNamedStyle: src/core/qgsmaplayer.h#L1213 +QgsMapLayer.loadNamedStyle: src/core/qgsmaplayer.h#L794 +QgsMapLayer.loadNamedStyleFromDatabase: src/core/qgsmaplayer.h#L1222 +QgsMapLayer.loadSldStyle: src/core/qgsmaplayer.h#L1340 +QgsMapLayer.mapTipTemplate: src/core/qgsmaplayer.h#L1775 +QgsMapLayer.mapTipTemplateChanged: src/core/qgsmaplayer.h#L2131 +QgsMapLayer.mapTipsEnabled: src/core/qgsmaplayer.h#L1798 +QgsMapLayer.mapTipsEnabledChanged: src/core/qgsmaplayer.h#L2139 +QgsMapLayer.maximumScale: src/core/qgsmaplayer.h#L1583 +QgsMapLayer.metadataChanged: src/core/qgsmaplayer.h#L2068 +QgsMapLayer.metadataUri: src/core/qgsmaplayer.h#L1088 QgsMapLayer.metadataUrl: src/core/qgsmaplayer.h#L460 QgsMapLayer.metadataUrlFormat: src/core/qgsmaplayer.h#L502 QgsMapLayer.metadataUrlType: src/core/qgsmaplayer.h#L481 -QgsMapLayer.minimumScale: src/core/qgsmaplayer.h#L1568 +QgsMapLayer.minimumScale: src/core/qgsmaplayer.h#L1571 QgsMapLayer.name: src/core/qgsmaplayer.h#L296 -QgsMapLayer.nameChanged: src/core/qgsmaplayer.h#L1934 +QgsMapLayer.nameChanged: src/core/qgsmaplayer.h#L1937 QgsMapLayer.opacity: src/core/qgsmaplayer.h#L535 -QgsMapLayer.opacityChanged: src/core/qgsmaplayer.h#L1999 -QgsMapLayer.originalXmlProperties: src/core/qgsmaplayer.h#L1694 -QgsMapLayer.project: src/core/qgsmaplayer.h#L1906 +QgsMapLayer.opacityChanged: src/core/qgsmaplayer.h#L2002 +QgsMapLayer.originalXmlProperties: src/core/qgsmaplayer.h#L1697 +QgsMapLayer.project: src/core/qgsmaplayer.h#L1909 QgsMapLayer.properties: src/core/qgsmaplayer.h#L253 QgsMapLayer.providerMetadata: src/core/qgsmaplayer.h#L313 -QgsMapLayer.providerReadFlags: src/core/qgsmaplayer.h#L1804 -QgsMapLayer.providerType: src/core/qgsmaplayer.h#L1492 -QgsMapLayer.publicSource: src/core/qgsmaplayer.h#L583 -QgsMapLayer.readCommonStyle: src/core/qgsmaplayer.h#L2243 -QgsMapLayer.readCustomProperties: src/core/qgsmaplayer.h#L2223 -QgsMapLayer.readLayerXml: src/core/qgsmaplayer.h#L675 +QgsMapLayer.providerReadFlags: src/core/qgsmaplayer.h#L1807 +QgsMapLayer.providerType: src/core/qgsmaplayer.h#L1495 +QgsMapLayer.publicSource: src/core/qgsmaplayer.h#L586 +QgsMapLayer.readCommonStyle: src/core/qgsmaplayer.h#L2246 +QgsMapLayer.readCustomProperties: src/core/qgsmaplayer.h#L2226 +QgsMapLayer.readLayerXml: src/core/qgsmaplayer.h#L678 QgsMapLayer.readOnly: src/core/qgsmaplayer.h#L538 -QgsMapLayer.readSld: src/core/qgsmaplayer.h#L1340 -QgsMapLayer.readStyle: src/core/qgsmaplayer.h#L1364 -QgsMapLayer.readStyleManager: src/core/qgsmaplayer.h#L2229 -QgsMapLayer.readSymbology: src/core/qgsmaplayer.h#L1352 -QgsMapLayer.readXml: src/core/qgsmaplayer.h#L2183 -QgsMapLayer.recalculateExtents: src/core/qgsmaplayer.h#L1983 -QgsMapLayer.refreshOnNotifyMessage: src/core/qgsmaplayer.h#L1678 +QgsMapLayer.readSld: src/core/qgsmaplayer.h#L1343 +QgsMapLayer.readStyle: src/core/qgsmaplayer.h#L1367 +QgsMapLayer.readStyleManager: src/core/qgsmaplayer.h#L2232 +QgsMapLayer.readSymbology: src/core/qgsmaplayer.h#L1355 +QgsMapLayer.readXml: src/core/qgsmaplayer.h#L2186 +QgsMapLayer.recalculateExtents: src/core/qgsmaplayer.h#L1986 +QgsMapLayer.refreshOnNotifyMessage: src/core/qgsmaplayer.h#L1681 QgsMapLayer.reload: src/core/qgsmaplayer.h#L543 -QgsMapLayer.removeCustomProperty: src/core/qgsmaplayer.h#L970 -QgsMapLayer.renderer3D: src/core/qgsmaplayer.h#L1546 -QgsMapLayer.renderer3DChanged: src/core/qgsmaplayer.h#L2027 -QgsMapLayer.rendererChanged: src/core/qgsmaplayer.h#L2005 -QgsMapLayer.repaintRequested: src/core/qgsmaplayer.h#L1980 -QgsMapLayer.request3DUpdate: src/core/qgsmaplayer.h#L2034 -QgsMapLayer.resolveReferences: src/core/qgsmaplayer.h#L698 -QgsMapLayer.saveDefaultMetadata: src/core/qgsmaplayer.h#L1102 -QgsMapLayer.saveDefaultStyle: src/core/qgsmaplayer.h#L1274 -QgsMapLayer.saveDefaultStyle: src/core/qgsmaplayer.h#L1287 -QgsMapLayer.saveNamedMetadata: src/core/qgsmaplayer.h#L1117 -QgsMapLayer.saveNamedStyle: src/core/qgsmaplayer.h#L1304 -QgsMapLayer.saveSldStyle: src/core/qgsmaplayer.h#L1315 -QgsMapLayer.saveSldStyleV2: src/core/qgsmaplayer.h#L1327 -QgsMapLayer.saveStyleToDatabase: src/core/qgsmaplayer.h#L772 -QgsMapLayer.selectionProperties: src/core/qgsmaplayer.h#L1727 +QgsMapLayer.removeCustomProperty: src/core/qgsmaplayer.h#L973 +QgsMapLayer.renderer3D: src/core/qgsmaplayer.h#L1549 +QgsMapLayer.renderer3DChanged: src/core/qgsmaplayer.h#L2030 +QgsMapLayer.rendererChanged: src/core/qgsmaplayer.h#L2008 +QgsMapLayer.repaintRequested: src/core/qgsmaplayer.h#L1983 +QgsMapLayer.request3DUpdate: src/core/qgsmaplayer.h#L2037 +QgsMapLayer.resolveReferences: src/core/qgsmaplayer.h#L701 +QgsMapLayer.saveDefaultMetadata: src/core/qgsmaplayer.h#L1105 +QgsMapLayer.saveDefaultStyle: src/core/qgsmaplayer.h#L1277 +QgsMapLayer.saveDefaultStyle: src/core/qgsmaplayer.h#L1290 +QgsMapLayer.saveNamedMetadata: src/core/qgsmaplayer.h#L1120 +QgsMapLayer.saveNamedStyle: src/core/qgsmaplayer.h#L1307 +QgsMapLayer.saveSldStyle: src/core/qgsmaplayer.h#L1318 +QgsMapLayer.saveSldStyleV2: src/core/qgsmaplayer.h#L1330 +QgsMapLayer.saveStyleToDatabase: src/core/qgsmaplayer.h#L775 +QgsMapLayer.selectionProperties: src/core/qgsmaplayer.h#L1730 QgsMapLayer.serverProperties: src/core/qgsmaplayer.h#L434 QgsMapLayer.setAbstract: src/core/qgsmaplayer.h#L348 QgsMapLayer.setAttribution: src/core/qgsmaplayer.h#L404 QgsMapLayer.setAttributionUrl: src/core/qgsmaplayer.h#L418 -QgsMapLayer.setAutoRefreshEnabled: src/core/qgsmaplayer.h#L1634 -QgsMapLayer.setAutoRefreshInterval: src/core/qgsmaplayer.h#L1626 -QgsMapLayer.setAutoRefreshMode: src/core/qgsmaplayer.h#L1642 +QgsMapLayer.setAutoRefreshEnabled: src/core/qgsmaplayer.h#L1637 +QgsMapLayer.setAutoRefreshInterval: src/core/qgsmaplayer.h#L1629 +QgsMapLayer.setAutoRefreshMode: src/core/qgsmaplayer.h#L1645 QgsMapLayer.setBlendMode: src/core/qgsmaplayer.h#L509 -QgsMapLayer.setCrs: src/core/qgsmaplayer.h#L1042 -QgsMapLayer.setCustomProperties: src/core/qgsmaplayer.h#L722 -QgsMapLayer.setCustomProperty: src/core/qgsmaplayer.h#L711 -QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1425 -QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1456 -QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1487 +QgsMapLayer.setCrs: src/core/qgsmaplayer.h#L1045 +QgsMapLayer.setCustomProperties: src/core/qgsmaplayer.h#L725 +QgsMapLayer.setCustomProperty: src/core/qgsmaplayer.h#L714 +QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1428 +QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1459 +QgsMapLayer.setDataSource: src/core/qgsmaplayer.h#L1490 QgsMapLayer.setDataUrl: src/core/qgsmaplayer.h#L376 QgsMapLayer.setDataUrlFormat: src/core/qgsmaplayer.h#L390 -QgsMapLayer.setDependencies: src/core/qgsmaplayer.h#L1869 -QgsMapLayer.setError: src/core/qgsmaplayer.h#L2259 -QgsMapLayer.setExtent3D: src/core/qgsmaplayer.h#L2174 -QgsMapLayer.setExtent: src/core/qgsmaplayer.h#L2168 +QgsMapLayer.setDependencies: src/core/qgsmaplayer.h#L1872 +QgsMapLayer.setError: src/core/qgsmaplayer.h#L2262 +QgsMapLayer.setExtent3D: src/core/qgsmaplayer.h#L2177 +QgsMapLayer.setExtent: src/core/qgsmaplayer.h#L2171 QgsMapLayer.setFlags: src/core/qgsmaplayer.h#L242 QgsMapLayer.setId: src/core/qgsmaplayer.h#L284 QgsMapLayer.setKeywordList: src/core/qgsmaplayer.h#L362 -QgsMapLayer.setLayerOrder: src/core/qgsmaplayer.h#L602 -QgsMapLayer.setLegend: src/core/qgsmaplayer.h#L1526 -QgsMapLayer.setLegendPlaceholderImage: src/core/qgsmaplayer.h#L1755 -QgsMapLayer.setLegendUrl: src/core/qgsmaplayer.h#L1505 -QgsMapLayer.setLegendUrlFormat: src/core/qgsmaplayer.h#L1515 -QgsMapLayer.setMapTipTemplate: src/core/qgsmaplayer.h#L1781 -QgsMapLayer.setMapTipsEnabled: src/core/qgsmaplayer.h#L1789 -QgsMapLayer.setMaximumScale: src/core/qgsmaplayer.h#L1828 -QgsMapLayer.setMetadata: src/core/qgsmaplayer.h#L1656 +QgsMapLayer.setLayerOrder: src/core/qgsmaplayer.h#L605 +QgsMapLayer.setLegend: src/core/qgsmaplayer.h#L1529 +QgsMapLayer.setLegendPlaceholderImage: src/core/qgsmaplayer.h#L1758 +QgsMapLayer.setLegendUrl: src/core/qgsmaplayer.h#L1508 +QgsMapLayer.setLegendUrlFormat: src/core/qgsmaplayer.h#L1518 +QgsMapLayer.setMapTipTemplate: src/core/qgsmaplayer.h#L1784 +QgsMapLayer.setMapTipsEnabled: src/core/qgsmaplayer.h#L1792 +QgsMapLayer.setMaximumScale: src/core/qgsmaplayer.h#L1831 +QgsMapLayer.setMetadata: src/core/qgsmaplayer.h#L1659 QgsMapLayer.setMetadataUrl: src/core/qgsmaplayer.h#L449 QgsMapLayer.setMetadataUrlFormat: src/core/qgsmaplayer.h#L491 QgsMapLayer.setMetadataUrlType: src/core/qgsmaplayer.h#L470 -QgsMapLayer.setMinimumScale: src/core/qgsmaplayer.h#L1817 +QgsMapLayer.setMinimumScale: src/core/qgsmaplayer.h#L1820 QgsMapLayer.setName: src/core/qgsmaplayer.h#L290 QgsMapLayer.setOpacity: src/core/qgsmaplayer.h#L525 -QgsMapLayer.setOriginalXmlProperties: src/core/qgsmaplayer.h#L1703 -QgsMapLayer.setProviderType: src/core/qgsmaplayer.h#L2247 -QgsMapLayer.setRefreshOnNofifyMessage: src/core/qgsmaplayer.h#L1883 -QgsMapLayer.setRefreshOnNotifyEnabled: src/core/qgsmaplayer.h#L1875 -QgsMapLayer.setRenderer3D: src/core/qgsmaplayer.h#L1541 -QgsMapLayer.setScaleBasedVisibility: src/core/qgsmaplayer.h#L1837 +QgsMapLayer.setOriginalXmlProperties: src/core/qgsmaplayer.h#L1706 +QgsMapLayer.setProviderType: src/core/qgsmaplayer.h#L2250 +QgsMapLayer.setRefreshOnNofifyMessage: src/core/qgsmaplayer.h#L1886 +QgsMapLayer.setRefreshOnNotifyEnabled: src/core/qgsmaplayer.h#L1878 +QgsMapLayer.setRenderer3D: src/core/qgsmaplayer.h#L1544 +QgsMapLayer.setScaleBasedVisibility: src/core/qgsmaplayer.h#L1840 QgsMapLayer.setShortName: src/core/qgsmaplayer.h#L320 -QgsMapLayer.setSubLayerVisibility: src/core/qgsmaplayer.h#L609 +QgsMapLayer.setSubLayerVisibility: src/core/qgsmaplayer.h#L612 QgsMapLayer.setTitle: src/core/qgsmaplayer.h#L334 -QgsMapLayer.setTransformContext: src/core/qgsmaplayer.h#L1890 -QgsMapLayer.setValid: src/core/qgsmaplayer.h#L2177 -QgsMapLayer.setVerticalCrs: src/core/qgsmaplayer.h#L1063 +QgsMapLayer.setTransformContext: src/core/qgsmaplayer.h#L1893 +QgsMapLayer.setValid: src/core/qgsmaplayer.h#L2180 +QgsMapLayer.setVerticalCrs: src/core/qgsmaplayer.h#L1066 QgsMapLayer.shortName: src/core/qgsmaplayer.h#L327 -QgsMapLayer.source: src/core/qgsmaplayer.h#L590 -QgsMapLayer.statusChanged: src/core/qgsmaplayer.h#L1919 -QgsMapLayer.styleChanged: src/core/qgsmaplayer.h#L2017 -QgsMapLayer.styleLoaded: src/core/qgsmaplayer.h#L2089 -QgsMapLayer.styleManager: src/core/qgsmaplayer.h#L1536 -QgsMapLayer.styleURI: src/core/qgsmaplayer.h#L1175 -QgsMapLayer.subLayers: src/core/qgsmaplayer.h#L596 -QgsMapLayer.supportsEditing: src/core/qgsmaplayer.h#L617 -QgsMapLayer.temporalProperties: src/core/qgsmaplayer.h#L1734 -QgsMapLayer.timestamp: src/core/qgsmaplayer.h#L1664 +QgsMapLayer.source: src/core/qgsmaplayer.h#L593 +QgsMapLayer.statusChanged: src/core/qgsmaplayer.h#L1922 +QgsMapLayer.styleChanged: src/core/qgsmaplayer.h#L2020 +QgsMapLayer.styleLoaded: src/core/qgsmaplayer.h#L2092 +QgsMapLayer.styleManager: src/core/qgsmaplayer.h#L1539 +QgsMapLayer.styleURI: src/core/qgsmaplayer.h#L1178 +QgsMapLayer.subLayers: src/core/qgsmaplayer.h#L599 +QgsMapLayer.supportsEditing: src/core/qgsmaplayer.h#L620 +QgsMapLayer.temporalProperties: src/core/qgsmaplayer.h#L1737 +QgsMapLayer.timestamp: src/core/qgsmaplayer.h#L1667 QgsMapLayer.title: src/core/qgsmaplayer.h#L341 -QgsMapLayer.transformContext: src/core/qgsmaplayer.h#L1070 -QgsMapLayer.trigger3DUpdate: src/core/qgsmaplayer.h#L1855 -QgsMapLayer.triggerRepaint: src/core/qgsmaplayer.h#L1847 +QgsMapLayer.transformContext: src/core/qgsmaplayer.h#L1073 +QgsMapLayer.trigger3DUpdate: src/core/qgsmaplayer.h#L1858 +QgsMapLayer.triggerRepaint: src/core/qgsmaplayer.h#L1850 QgsMapLayer.type: src/core/qgsmaplayer.h#L218 -QgsMapLayer.undoStack: src/core/qgsmaplayer.h#L1495 -QgsMapLayer.undoStackStyles: src/core/qgsmaplayer.h#L1500 -QgsMapLayer.verticalCrs: src/core/qgsmaplayer.h#L1010 -QgsMapLayer.verticalCrsChanged: src/core/qgsmaplayer.h#L1972 +QgsMapLayer.undoStack: src/core/qgsmaplayer.h#L1498 +QgsMapLayer.undoStackStyles: src/core/qgsmaplayer.h#L1503 +QgsMapLayer.verticalCrs: src/core/qgsmaplayer.h#L1013 +QgsMapLayer.verticalCrsChanged: src/core/qgsmaplayer.h#L1975 QgsMapLayer.wgs84Extent: src/core/qgsmaplayer.h#L567 -QgsMapLayer.willBeDeleted: src/core/qgsmaplayer.h#L2052 -QgsMapLayer.writeCommonStyle: src/core/qgsmaplayer.h#L2236 -QgsMapLayer.writeCustomProperties: src/core/qgsmaplayer.h#L2226 -QgsMapLayer.writeLayerXml: src/core/qgsmaplayer.h#L693 -QgsMapLayer.writeStyle: src/core/qgsmaplayer.h#L1391 -QgsMapLayer.writeStyleManager: src/core/qgsmaplayer.h#L2231 -QgsMapLayer.writeSymbology: src/core/qgsmaplayer.h#L1377 -QgsMapLayer.writeXml: src/core/qgsmaplayer.h#L2189 +QgsMapLayer.willBeDeleted: src/core/qgsmaplayer.h#L2055 +QgsMapLayer.writeCommonStyle: src/core/qgsmaplayer.h#L2239 +QgsMapLayer.writeCustomProperties: src/core/qgsmaplayer.h#L2229 +QgsMapLayer.writeLayerXml: src/core/qgsmaplayer.h#L696 +QgsMapLayer.writeStyle: src/core/qgsmaplayer.h#L1394 +QgsMapLayer.writeStyleManager: src/core/qgsmaplayer.h#L2234 +QgsMapLayer.writeSymbology: src/core/qgsmaplayer.h#L1380 +QgsMapLayer.writeXml: src/core/qgsmaplayer.h#L2192 QgsMapLayer: src/core/qgsmaplayer.h#L75 QgsMapLayerDependency.__hash__: src/core/qgsmaplayerdependency.h#L78 QgsMapLayerDependency.layerId: src/core/qgsmaplayerdependency.h#L67 From 39260ec8955110e0e255f38cf80089df0ca19a05 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Sun, 2 Feb 2025 14:26:35 +0700 Subject: [PATCH 75/81] [georeferencer] Fix the layer -> georeferencer menu action when in dock panel mode --- src/app/georeferencer/qgsgeorefmainwindow.cpp | 13 +++++++++++++ src/app/georeferencer/qgsgeorefmainwindow.h | 2 ++ src/app/qgisapp.cpp | 5 +++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/app/georeferencer/qgsgeorefmainwindow.cpp b/src/app/georeferencer/qgsgeorefmainwindow.cpp index 726d6d62df87f..a9fb53cc78746 100644 --- a/src/app/georeferencer/qgsgeorefmainwindow.cpp +++ b/src/app/georeferencer/qgsgeorefmainwindow.cpp @@ -148,6 +148,19 @@ QgsGeoreferencerMainWindow::QgsGeoreferencerMainWindow( QWidget *parent, Qt::Win } } +void QgsGeoreferencerMainWindow::showGeoreferencer() +{ + if ( mDock ) + { + mDock->setUserVisible( true ); + } + else + { + show(); + setFocus(); + } +} + void QgsGeoreferencerMainWindow::dockThisWindow( bool dock ) { if ( mDock ) diff --git a/src/app/georeferencer/qgsgeorefmainwindow.h b/src/app/georeferencer/qgsgeorefmainwindow.h index 0998f2b5b5890..4d0dc9b8a4dd2 100644 --- a/src/app/georeferencer/qgsgeorefmainwindow.h +++ b/src/app/georeferencer/qgsgeorefmainwindow.h @@ -85,6 +85,8 @@ class APP_EXPORT QgsGeoreferencerMainWindow : public QMainWindow, private Ui::Qg QgsGeoreferencerMainWindow( QWidget *parent = nullptr, Qt::WindowFlags fl = Qt::WindowFlags() ); ~QgsGeoreferencerMainWindow() override; + void showGeoreferencer(); + protected: void closeEvent( QCloseEvent * ) override; void dropEvent( QDropEvent *event ) override; diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index b94d4964fcf0b..e5d32576f9999 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -782,9 +782,10 @@ void QgisApp::toggleEventTracing() void QgisApp::showGeoreferencer() { if ( !mGeoreferencer ) + { mGeoreferencer = new QgsGeoreferencerMainWindow( this ); - mGeoreferencer->show(); - mGeoreferencer->setFocus(); + } + mGeoreferencer->showGeoreferencer(); } #endif From fcff471869fe21096b7c5f8f581230821a41f12c Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 22 Jan 2025 11:54:39 +0100 Subject: [PATCH 76/81] fix handling empty raster column --- .../raster/qgspostgresrasterprovider.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/providers/postgres/raster/qgspostgresrasterprovider.cpp b/src/providers/postgres/raster/qgspostgresrasterprovider.cpp index a7db889b95ea2..f4670e4f1233d 100644 --- a/src/providers/postgres/raster/qgspostgresrasterprovider.cpp +++ b/src/providers/postgres/raster/qgspostgresrasterprovider.cpp @@ -2491,13 +2491,13 @@ bool QgsPostgresRasterProviderMetadata::styleExists( const QString &uri, const Q " AND f_geometry_column IS NULL" " AND (type=%4 OR type IS NULL)" " AND styleName=%5" - " AND r_raster_column=%6" ) + " AND r_raster_column %6" ) .arg( QgsPostgresConn::quotedValue( dsUri.database() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.schema() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.table() ) ) .arg( QgsPostgresConn::quotedValue( mType ) ) .arg( QgsPostgresConn::quotedValue( styleId.isEmpty() ? dsUri.table() : styleId ) ) - .arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ); + .arg( dsUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "= %1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) ); QgsPostgresResult res( conn->LoggedPQexec( QStringLiteral( "QgsPostgresRasterProviderMetadata" ), checkQuery ) ); if ( res.PQresultStatus() == PGRES_TUPLES_OK ) @@ -2609,13 +2609,13 @@ bool QgsPostgresRasterProviderMetadata::saveStyle( const QString &uri, const QSt " AND f_geometry_column IS NULL" " AND (type=%4 OR type IS NULL)" " AND styleName=%5" - " AND r_raster_column=%6" ) + " AND r_raster_column %6" ) .arg( QgsPostgresConn::quotedValue( dsUri.database() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.schema() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.table() ) ) .arg( QgsPostgresConn::quotedValue( mType ) ) .arg( QgsPostgresConn::quotedValue( styleName.isEmpty() ? dsUri.table() : styleName ) ) - .arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ); + .arg( dsUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "= %1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) ); QgsPostgresResult res( conn->LoggedPQexec( "QgsPostgresRasterProviderMetadata", checkQuery ) ); if ( res.PQntuples() > 0 ) @@ -2633,7 +2633,7 @@ bool QgsPostgresRasterProviderMetadata::saveStyle( const QString &uri, const QSt " AND f_geometry_column IS NULL" " AND styleName=%9" " AND (type=%2 OR type IS NULL)" - " AND r_raster_column=%14" ) + " AND r_raster_column %14" ) .arg( useAsDefault ? "true" : "false" ) .arg( QgsPostgresConn::quotedValue( mType ) ) .arg( QgsPostgresConn::quotedValue( styleDescription.isEmpty() ? QDateTime::currentDateTime().toString() : styleDescription ) ) @@ -2644,7 +2644,7 @@ bool QgsPostgresRasterProviderMetadata::saveStyle( const QString &uri, const QSt .arg( QgsPostgresConn::quotedValue( styleName.isEmpty() ? dsUri.table() : styleName ) ) // Must be the final .arg replacement - see above .arg( QgsPostgresConn::quotedValue( qmlStyle ), QgsPostgresConn::quotedValue( sldStyle ) ) - .arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ); + .arg( dsUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "= %1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) ); } if ( useAsDefault ) @@ -2656,12 +2656,12 @@ bool QgsPostgresRasterProviderMetadata::saveStyle( const QString &uri, const QSt " AND f_table_name=%3" " AND f_geometry_column IS NULL" " AND (type=%4 OR type IS NULL)" - " AND r_raster_column=%5" ) + " AND r_raster_column %5" ) .arg( QgsPostgresConn::quotedValue( dsUri.database() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.schema() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.table() ) ) .arg( QgsPostgresConn::quotedValue( mType ) ) - .arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ); + .arg( dsUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "= %1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) ); sql = QStringLiteral( "BEGIN; %1; %2; COMMIT;" ).arg( removeDefaultSql, sql ); } @@ -2720,13 +2720,13 @@ QString QgsPostgresRasterProviderMetadata::loadStoredStyle( const QString &uri, " AND f_table_schema=%2" " AND f_table_name=%3" " AND f_geometry_column IS NULL" - " AND r_raster_column=%4" + " AND r_raster_column %4" " ORDER BY CASE WHEN useAsDefault THEN 1 ELSE 2 END" ",update_time DESC LIMIT 1" ) .arg( QgsPostgresConn::quotedValue( dsUri.database() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.schema() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.table() ) ) - .arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ); + .arg( dsUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "= %1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) ); } else { @@ -2737,14 +2737,14 @@ QString QgsPostgresRasterProviderMetadata::loadStoredStyle( const QString &uri, " AND f_table_name=%3" " AND f_geometry_column IS NULL" " AND (type=%4 OR type IS NULL)" - " AND r_raster_column=%5" + " AND r_raster_column %5" " ORDER BY CASE WHEN useAsDefault THEN 1 ELSE 2 END" ",update_time DESC LIMIT 1" ) .arg( QgsPostgresConn::quotedValue( dsUri.database() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.schema() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.table() ) ) .arg( QgsPostgresConn::quotedValue( mType ) ) - .arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ); + .arg( dsUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "= %1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) ); } QgsPostgresResult result( conn->LoggedPQexec( QStringLiteral( "QgsPostgresRasterProviderMetadata" ), selectQmlQuery ) ); @@ -2792,13 +2792,13 @@ int QgsPostgresRasterProviderMetadata::listStyles( const QString &uri, QStringLi " AND f_table_name=%3" " AND f_geometry_column is NULL" " AND (type=%4 OR type IS NULL)" - " AND r_raster_column=%5" + " AND r_raster_column %5" " ORDER BY useasdefault DESC, update_time DESC" ) .arg( QgsPostgresConn::quotedValue( dsUri.database() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.schema() ) ) .arg( QgsPostgresConn::quotedValue( dsUri.table() ) ) .arg( QgsPostgresConn::quotedValue( mType ) ) - .arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ); + .arg( dsUri.geometryColumn().isEmpty() ? QStringLiteral( "IS NULL" ) : QStringLiteral( "= %1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) ); QgsPostgresResult result( conn->LoggedPQexec( QStringLiteral( "QgsPostgresRasterProviderMetadata" ), selectRelatedQuery ) ); if ( result.PQresultStatus() != PGRES_TUPLES_OK ) From 6935c134d991dafc5b65a1db1a4a2acc0e4c0b6e Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 22 Jan 2025 11:55:18 +0100 Subject: [PATCH 77/81] add tests for raster style saving in postgresql db --- .../python/test_provider_postgresraster.py | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/tests/src/python/test_provider_postgresraster.py b/tests/src/python/test_provider_postgresraster.py index 940429c60a180..9f410451c9fd0 100644 --- a/tests/src/python/test_provider_postgresraster.py +++ b/tests/src/python/test_provider_postgresraster.py @@ -1012,6 +1012,94 @@ def testBlockSize(self): self.assertEqual(dp.xBlockSize(), 2) self.assertEqual(dp.yBlockSize(), 2) + def testStyle(self): + rl = QgsRasterLayer( + self.dbconn + + ' sslmode=disable srid=3035 table="public"."raster_tiled_3035" sql=', + "test", + "postgresraster", + ) + + self.assertTrue(rl.isValid()) + + self.assertEqual( + int(rl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + Qgis.ProviderStyleStorageCapability.LoadFromDatabase, + ) + self.assertEqual( + int(rl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.SaveToDatabase, + Qgis.ProviderStyleStorageCapability.SaveToDatabase, + ) + self.assertEqual( + int(rl.dataProvider().styleStorageCapabilities()) + & Qgis.ProviderStyleStorageCapability.DeleteFromDatabase, + Qgis.ProviderStyleStorageCapability.DeleteFromDatabase, + ) + + # not style yet for layer + res, err = QgsProviderRegistry.instance().styleExists( + "postgresraster", rl.source(), "" + ) + self.assertFalse(res) + self.assertFalse(err) + + related_count, idlist, namelist, desclist, errmsg = rl.listStylesInDatabase() + self.assertEqual(related_count, -1) + self.assertEqual(idlist, []) + self.assertEqual(namelist, []) + self.assertEqual(desclist, []) + self.assertFalse(errmsg) + + # Save style twice, one as as default + errmsg = rl.saveStyleToDatabase("related raster style", "test style", False, "") + self.assertEqual(errmsg, "") + + related_count, idlist, namelist, desclist, errmsg = rl.listStylesInDatabase() + self.assertEqual(related_count, 1) + self.assertEqual(idlist, ["1"]) + self.assertEqual(namelist, ["related raster style"]) + self.assertEqual(desclist, ["test style"]) + self.assertFalse(errmsg) + + errmsg = rl.saveStyleToDatabase( + "related raster style default", "default test style", True, "" + ) + self.assertEqual(errmsg, "") + + # check style exist + res, err = QgsProviderRegistry.instance().styleExists( + "postgresraster", rl.source(), "related raster style default" + ) + self.assertTrue(res) + self.assertFalse(err) + + qml, errmsg = rl.getStyleFromDatabase("2") + self.assertTrue(qml) + self.assertEqual(errmsg, "") + + related_count, idlist, namelist, desclist, errmsg = rl.listStylesInDatabase() + self.assertEqual(related_count, 2) + self.assertEqual(idlist, ["2", "1"]) + self.assertEqual( + namelist, ["related raster style default", "related raster style"] + ) + self.assertEqual(desclist, ["default test style", "test style"]) + self.assertFalse(errmsg) + + # Remove these style + res, errmsg = rl.deleteStyleFromDatabase("1") + self.assertTrue(res) + self.assertFalse(errmsg) + + related_count, idlist, namelist, desclist, errmsg = rl.listStylesInDatabase() + self.assertEqual(related_count, 1) + self.assertEqual(idlist, ["2"]) + self.assertEqual(namelist, ["related raster style default"]) + self.assertEqual(desclist, ["default test style"]) + self.assertFalse(errmsg) + if __name__ == "__main__": unittest.main() From edc5453f39720bc8fd4b5e665e6d9487ce407283 Mon Sep 17 00:00:00 2001 From: Jan Caha Date: Wed, 22 Jan 2025 12:14:42 +0100 Subject: [PATCH 78/81] add test case with specified raster column --- .../python/test_provider_postgresraster.py | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/src/python/test_provider_postgresraster.py b/tests/src/python/test_provider_postgresraster.py index 9f410451c9fd0..5ecd291fd0ace 100644 --- a/tests/src/python/test_provider_postgresraster.py +++ b/tests/src/python/test_provider_postgresraster.py @@ -1100,6 +1100,80 @@ def testStyle(self): self.assertEqual(desclist, ["default test style"]) self.assertFalse(errmsg) + # Raster layer with defined column + rl_1 = QgsRasterLayer( + self.dbconn + + ' sslmode=disable srid=3035 table="public"."raster_tiled_3035" (rast) sql=', + "test", + "postgresraster", + ) + + self.assertTrue(rl_1.isValid()) + + # not style yet for layer + res, err = QgsProviderRegistry.instance().styleExists( + "postgresraster", rl_1.source(), "" + ) + self.assertFalse(res) + self.assertFalse(err) + + related_count, idlist, namelist, desclist, errmsg = rl_1.listStylesInDatabase() + self.assertEqual(related_count, 0) + self.assertEqual(idlist, []) + self.assertEqual(namelist, []) + self.assertEqual(desclist, []) + self.assertFalse(errmsg) + + # Save style twice, one as as default + errmsg = rl_1.saveStyleToDatabase( + "related raster style", "test style", False, "" + ) + self.assertEqual(errmsg, "") + + related_count, idlist, namelist, desclist, errmsg = rl_1.listStylesInDatabase() + self.assertEqual(related_count, 1) + self.assertEqual(idlist, ["3"]) + self.assertEqual(namelist, ["related raster style"]) + self.assertEqual(desclist, ["test style"]) + self.assertFalse(errmsg) + + errmsg = rl_1.saveStyleToDatabase( + "related raster style default", "default test style", True, "" + ) + self.assertEqual(errmsg, "") + + # check style exist + res, err = QgsProviderRegistry.instance().styleExists( + "postgresraster", rl_1.source(), "related raster style default" + ) + self.assertTrue(res) + self.assertFalse(err) + + qml, errmsg = rl_1.getStyleFromDatabase("3") + self.assertTrue(qml) + self.assertEqual(errmsg, "") + + related_count, idlist, namelist, desclist, errmsg = rl_1.listStylesInDatabase() + self.assertEqual(related_count, 2) + self.assertEqual(idlist, ["4", "3"]) + self.assertEqual( + namelist, ["related raster style default", "related raster style"] + ) + self.assertEqual(desclist, ["default test style", "test style"]) + self.assertFalse(errmsg) + + # Remove these style + res, errmsg = rl_1.deleteStyleFromDatabase("3") + self.assertTrue(res) + self.assertFalse(errmsg) + + related_count, idlist, namelist, desclist, errmsg = rl_1.listStylesInDatabase() + self.assertEqual(related_count, 1) + self.assertEqual(idlist, ["4"]) + self.assertEqual(namelist, ["related raster style default"]) + self.assertEqual(desclist, ["default test style"]) + self.assertFalse(errmsg) + if __name__ == "__main__": unittest.main() From beb2b1d525015870a2f306056ae3b0038de68d6a Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 3 Feb 2025 14:14:19 +1000 Subject: [PATCH 79/81] Avoid coverity warning about wrapper use after free Should not be a real problem, but for safety delete the warp options before the dataset handles can possibly be deleted --- src/app/georeferencer/qgsimagewarper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/georeferencer/qgsimagewarper.cpp b/src/app/georeferencer/qgsimagewarper.cpp index 31430778536c7..b700d12aebddd 100644 --- a/src/app/georeferencer/qgsimagewarper.cpp +++ b/src/app/georeferencer/qgsimagewarper.cpp @@ -208,6 +208,8 @@ QgsImageWarper::Result QgsImageWarper::warpFile( const QString &input, const QSt eErr = oOperation.ChunkAndWarpImage( 0, 0, destPixels, destLines ); destroyGeoToPixelTransform( psWarpOptions->pTransformerArg ); + psWarpOptions.reset(); + return feedback->isCanceled() ? QgsImageWarper::Result::Canceled : eErr == CE_None ? QgsImageWarper::Result::Success : QgsImageWarper::Result::WarpFailure; } From 664abaafbef2bcf781cee5cbb895a4a8a7be64a7 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 3 Feb 2025 14:15:27 +1000 Subject: [PATCH 80/81] Remove redundant nullptr check --- src/core/pointcloud/qgspointcloudlayerrenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/pointcloud/qgspointcloudlayerrenderer.cpp b/src/core/pointcloud/qgspointcloudlayerrenderer.cpp index d3afec0657f76..054f59179c576 100644 --- a/src/core/pointcloud/qgspointcloudlayerrenderer.cpp +++ b/src/core/pointcloud/qgspointcloudlayerrenderer.cpp @@ -45,7 +45,7 @@ QgsPointCloudLayerRenderer::QgsPointCloudLayerRenderer( QgsPointCloudLayer *laye : QgsMapLayerRenderer( layer->id(), &context ) , mLayerName( layer->name() ) , mLayerAttributes( layer->attributes() ) - , mSubIndexes( layer && layer->dataProvider() ? layer->dataProvider()->subIndexes() : QVector() ) + , mSubIndexes( layer->dataProvider() ? layer->dataProvider()->subIndexes() : QVector() ) , mFeedback( new QgsFeedback ) , mEnableProfile( context.flags() & Qgis::RenderContextFlag::RecordProfile ) { From 3cca51bfc8e0b3f45cf1954b6a5bb75d38ddb1f9 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 3 Feb 2025 10:47:08 +1000 Subject: [PATCH 81/81] [sensorthings] only allow expansion removal from end of table Otherwise we can end up with inconsistent/invalid expansions Fixes #59532 --- .../qgssensorthingssourcewidget.cpp | 49 +++++++++++++++---- .../qgssensorthingssourcewidget.h | 1 + 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/gui/providers/sensorthings/qgssensorthingssourcewidget.cpp b/src/gui/providers/sensorthings/qgssensorthingssourcewidget.cpp index 0b818da61e2e1..0df2da7c05604 100644 --- a/src/gui/providers/sensorthings/qgssensorthingssourcewidget.cpp +++ b/src/gui/providers/sensorthings/qgssensorthingssourcewidget.cpp @@ -71,7 +71,11 @@ QgsSensorThingsSourceWidget::QgsSensorThingsSourceWidget( QWidget *parent ) connect( mExpansionsTable, &QTableView::clicked, this, [this]( const QModelIndex &index ) { if ( index.column() == QgsSensorThingsExpansionsModel::Column::Actions ) { - mExpansionsModel->removeRows( index.row(), 1 ); + // only the bottom expansion (or empty rows) can be removed - otherwise we end up with inconsistent expansions! + if ( mExpansionsModel->canRemoveRow( index.row() ) ) + { + mExpansionsModel->removeRows( index.row(), 1 ); + } } } ); @@ -722,6 +726,25 @@ bool QgsSensorThingsExpansionsModel::insertRows( int position, int rows, const Q return true; } +bool QgsSensorThingsExpansionsModel::canRemoveRow( int row ) const +{ + if ( row >= mExpansions.size() ) + return true; + + for ( int i = mExpansions.size() - 1; i >= 0; --i ) + { + if ( row == i && mExpansions.at( i ).isValid() ) + return true; + + // when we hit the first valid expansion from the end of the list, then + // any earlier rows CANNOT be removed + if ( mExpansions.at( i ).isValid() ) + return false; + } + + return false; +} + bool QgsSensorThingsExpansionsModel::removeRows( int position, int rows, const QModelIndex &parent ) { Q_UNUSED( parent ) @@ -957,19 +980,25 @@ void QgsSensorThingsRemoveExpansionDelegate::paint( QPainter *painter, const QSt { QStyledItemDelegate::paint( painter, option, index ); - if ( index == mHoveredIndex ) + if ( const QgsSensorThingsExpansionsModel *model = qobject_cast< const QgsSensorThingsExpansionsModel * >( index.model() ) ) { - QStyleOptionButton buttonOption; - buttonOption.initFrom( option.widget ); - buttonOption.rect = option.rect; + if ( model->canRemoveRow( index.row() ) ) + { + if ( index == mHoveredIndex ) + { + QStyleOptionButton buttonOption; + buttonOption.initFrom( option.widget ); + buttonOption.rect = option.rect; - option.widget->style()->drawControl( QStyle::CE_PushButton, &buttonOption, painter ); - } + option.widget->style()->drawControl( QStyle::CE_PushButton, &buttonOption, painter ); + } - const QIcon icon = QgsApplication::getThemeIcon( "/mIconClearItem.svg" ); - const QRect iconRect( option.rect.left() + ( option.rect.width() - 16 ) / 2, option.rect.top() + ( option.rect.height() - 16 ) / 2, 16, 16 ); + const QIcon icon = QgsApplication::getThemeIcon( "/mIconClearItem.svg" ); + const QRect iconRect( option.rect.left() + ( option.rect.width() - 16 ) / 2, option.rect.top() + ( option.rect.height() - 16 ) / 2, 16, 16 ); - icon.paint( painter, iconRect ); + icon.paint( painter, iconRect ); + } + } } void QgsSensorThingsRemoveExpansionDelegate::setHoveredIndex( const QModelIndex &index ) diff --git a/src/gui/providers/sensorthings/qgssensorthingssourcewidget.h b/src/gui/providers/sensorthings/qgssensorthingssourcewidget.h index 9ff8febac80fb..9386b2a4e1184 100644 --- a/src/gui/providers/sensorthings/qgssensorthingssourcewidget.h +++ b/src/gui/providers/sensorthings/qgssensorthingssourcewidget.h @@ -59,6 +59,7 @@ class QgsSensorThingsExpansionsModel : public QAbstractItemModel QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override; bool setData( const QModelIndex &index, const QVariant &value, int role ) override; bool insertRows( int position, int rows, const QModelIndex &parent = QModelIndex() ) override; + bool canRemoveRow( int row ) const; bool removeRows( int position, int rows, const QModelIndex &parent = QModelIndex() ) override; void setExpansions( const QList &expansions );