diff --git a/python/core/auto_generated/mesh/qgsmeshlayer.sip.in b/python/core/auto_generated/mesh/qgsmeshlayer.sip.in index 7e4d03d2a39..68410d2e3f3 100644 --- a/python/core/auto_generated/mesh/qgsmeshlayer.sip.in +++ b/python/core/auto_generated/mesh/qgsmeshlayer.sip.in @@ -155,6 +155,8 @@ QgsMeshLayer cannot be copied. virtual QgsMapLayerTemporalProperties *temporalProperties(); + virtual QgsMapLayerElevationProperties *elevationProperties(); + virtual void reload(); virtual QStringList subLayers() const; diff --git a/python/core/auto_generated/mesh/qgsmeshlayerelevationproperties.sip.in b/python/core/auto_generated/mesh/qgsmeshlayerelevationproperties.sip.in new file mode 100644 index 00000000000..bbe3f66ed4a --- /dev/null +++ b/python/core/auto_generated/mesh/qgsmeshlayerelevationproperties.sip.in @@ -0,0 +1,68 @@ +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/mesh/qgsmeshlayerelevationproperties.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ + + + + + + +class QgsMeshLayerElevationProperties : QgsMapLayerElevationProperties +{ +%Docstring(signature="appended") +Mesh layer specific subclass of :py:class:`QgsMapLayerElevationProperties`. + +.. versionadded:: 3.26 +%End + +%TypeHeaderCode +#include "qgsmeshlayerelevationproperties.h" +%End + public: + + QgsMeshLayerElevationProperties( QObject *parent /TransferThis/ ); +%Docstring +Constructor for QgsMeshLayerElevationProperties, with the specified ``parent`` object. +%End + ~QgsMeshLayerElevationProperties(); + + virtual bool hasElevation() const; + + virtual QDomElement writeXml( QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context ); + + virtual bool readXml( const QDomElement &element, const QgsReadWriteContext &context ); + + virtual bool isVisibleInZRange( const QgsDoubleRange &range ) const; + + virtual QgsDoubleRange calculateZRange( QgsMapLayer *layer ) const; + + + QgsLineSymbol *profileLineSymbol() const; +%Docstring +Returns the line symbol used to render the mesh profile in elevation profile plots. + +.. seealso:: :py:func:`setProfileLineSymbol` +%End + + void setProfileLineSymbol( QgsLineSymbol *symbol /Transfer/ ); +%Docstring +Sets the line ``symbol`` used to render the mesh profile in elevation profile plots. + +Ownership of ``symbol`` is transferred to the plot. + +.. seealso:: :py:func:`profileLineSymbol` +%End + +}; + +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/mesh/qgsmeshlayerelevationproperties.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ diff --git a/python/core/auto_generated/qgsmaplayerelevationproperties.sip.in b/python/core/auto_generated/qgsmaplayerelevationproperties.sip.in index 9aa9a11d4d6..ae8c6fa32ba 100644 --- a/python/core/auto_generated/qgsmaplayerelevationproperties.sip.in +++ b/python/core/auto_generated/qgsmaplayerelevationproperties.sip.in @@ -27,6 +27,7 @@ how an individual :py:class:`QgsMapLayer` behaves with relation to z values or e #include "qgspointcloudlayerelevationproperties.h" #include "qgsrasterlayerelevationproperties.h" #include "qgsvectorlayerelevationproperties.h" +#include "qgsmeshlayerelevationproperties.h" %End %ConvertToSubClassCode if ( qobject_cast( sipCpp ) ) @@ -41,6 +42,10 @@ how an individual :py:class:`QgsMapLayer` behaves with relation to z values or e { sipType = sipType_QgsRasterLayerElevationProperties; } + else if ( qobject_cast( sipCpp ) ) + { + sipType = sipType_QgsMeshLayerElevationProperties; + } else { sipType = 0; diff --git a/python/core/core_auto.sip b/python/core/core_auto.sip index 6f8c7ff2644..23c8441bd7d 100644 --- a/python/core/core_auto.sip +++ b/python/core/core_auto.sip @@ -444,6 +444,7 @@ %Include auto_generated/mesh/qgsmeshdataprovidertemporalcapabilities.sip %Include auto_generated/mesh/qgsmeshdataset.sip %Include auto_generated/mesh/qgsmeshlayer.sip +%Include auto_generated/mesh/qgsmeshlayerelevationproperties.sip %Include auto_generated/mesh/qgsmeshlayerinterpolator.sip %Include auto_generated/mesh/qgsmeshlayertemporalproperties.sip %Include auto_generated/mesh/qgsmeshrenderersettings.sip diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 165ae64bd57..a64aeef5b99 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -259,6 +259,7 @@ set(QGIS_APP_SRCS mesh/qgsmeshcalculatordialog.cpp mesh/qgsnewmeshlayerdialog.cpp mesh/qgsmaptooleditmeshframe.cpp + mesh/qgsmeshelevationpropertieswidget.cpp mesh/qgsmeshtransformcoordinatesdockwidget.cpp mesh/qgsmeshselectbyexpressiondialog.cpp diff --git a/src/app/mesh/qgsmeshelevationpropertieswidget.cpp b/src/app/mesh/qgsmeshelevationpropertieswidget.cpp new file mode 100644 index 00000000000..d54865868a4 --- /dev/null +++ b/src/app/mesh/qgsmeshelevationpropertieswidget.cpp @@ -0,0 +1,109 @@ +/*************************************************************************** + qgsmeshelevationpropertieswidget.cpp + --------------------- + begin : February 2022 + copyright : (C) 2022 by Nyall Dawson + email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsmeshelevationpropertieswidget.h" +#include "qgsstyle.h" +#include "qgsapplication.h" +#include "qgsmaplayer.h" +#include "qgsmeshlayer.h" +#include "qgsmeshlayerelevationproperties.h" +#include "qgslinesymbol.h" + +QgsMeshElevationPropertiesWidget::QgsMeshElevationPropertiesWidget( QgsMeshLayer *layer, QgsMapCanvas *canvas, QWidget *parent ) + : QgsMapLayerConfigWidget( layer, canvas, parent ) +{ + setupUi( this ); + + mOffsetZSpinBox->setClearValue( 0 ); + mScaleZSpinBox->setClearValue( 1 ); + mLineStyleButton->setSymbolType( Qgis::SymbolType::Line ); + + syncToLayer( layer ); + + connect( mOffsetZSpinBox, qOverload( &QDoubleSpinBox::valueChanged ), this, &QgsMeshElevationPropertiesWidget::onChanged ); + connect( mScaleZSpinBox, qOverload( &QDoubleSpinBox::valueChanged ), this, &QgsMeshElevationPropertiesWidget::onChanged ); + connect( mLineStyleButton, &QgsSymbolButton::changed, this, &QgsMeshElevationPropertiesWidget::onChanged ); +} + +void QgsMeshElevationPropertiesWidget::syncToLayer( QgsMapLayer *layer ) +{ + mLayer = qobject_cast< QgsMeshLayer * >( layer ); + if ( !mLayer ) + return; + + mBlockUpdates = true; + const QgsMeshLayerElevationProperties *props = qgis::down_cast< const QgsMeshLayerElevationProperties * >( mLayer->elevationProperties() ); + mOffsetZSpinBox->setValue( props->zOffset() ); + mScaleZSpinBox->setValue( props->zScale() ); + mLineStyleButton->setSymbol( props->profileLineSymbol()->clone() ); + + mBlockUpdates = false; +} + +void QgsMeshElevationPropertiesWidget::apply() +{ + if ( !mLayer ) + return; + + QgsMeshLayerElevationProperties *props = qgis::down_cast< QgsMeshLayerElevationProperties * >( mLayer->elevationProperties() ); + props->setZOffset( mOffsetZSpinBox->value() ); + props->setZScale( mScaleZSpinBox->value() ); + props->setProfileLineSymbol( mLineStyleButton->clonedSymbol< QgsLineSymbol >() ); + mLayer->trigger3DUpdate(); +} + +void QgsMeshElevationPropertiesWidget::onChanged() +{ + if ( !mBlockUpdates ) + emit widgetChanged(); +} + + +// +// QgsMeshElevationPropertiesWidgetFactory +// + +QgsMeshElevationPropertiesWidgetFactory::QgsMeshElevationPropertiesWidgetFactory( QObject *parent ) + : QObject( parent ) +{ + setIcon( QgsApplication::getThemeIcon( QStringLiteral( "propertyicons/elevationscale.svg" ) ) ); + setTitle( tr( "Elevation" ) ); +} + +QgsMapLayerConfigWidget *QgsMeshElevationPropertiesWidgetFactory::createWidget( QgsMapLayer *layer, QgsMapCanvas *canvas, bool, QWidget *parent ) const +{ + return new QgsMeshElevationPropertiesWidget( qobject_cast< QgsMeshLayer * >( layer ), canvas, parent ); +} + +bool QgsMeshElevationPropertiesWidgetFactory::supportLayerPropertiesDialog() const +{ + return true; +} + +bool QgsMeshElevationPropertiesWidgetFactory::supportsStyleDock() const +{ + return false; +} + +bool QgsMeshElevationPropertiesWidgetFactory::supportsLayer( QgsMapLayer *layer ) const +{ + return layer->type() == QgsMapLayerType::MeshLayer; +} + +QString QgsMeshElevationPropertiesWidgetFactory::layerPropertiesPagePositionHint() const +{ + return QStringLiteral( "mOptsPage_Metadata" ); +} + diff --git a/src/app/mesh/qgsmeshelevationpropertieswidget.h b/src/app/mesh/qgsmeshelevationpropertieswidget.h new file mode 100644 index 00000000000..2658e3a1f0f --- /dev/null +++ b/src/app/mesh/qgsmeshelevationpropertieswidget.h @@ -0,0 +1,65 @@ +/*************************************************************************** + qgsmeshelevationpropertieswidget.h + --------------------- + begin : February 2022 + copyright : (C) 2022 by Nyall Dawson + email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSMESHELEVATIONPROPERTIESWIDGET_H +#define QGSMESHELEVATIONPROPERTIESWIDGET_H + +#include "qgsmaplayerconfigwidget.h" +#include "qgsmaplayerconfigwidgetfactory.h" + +#include "ui_qgsmeshelevationpropertieswidgetbase.h" + +class QgsMeshLayer; + +class QgsMeshElevationPropertiesWidget : public QgsMapLayerConfigWidget, private Ui::QgsMeshElevationPropertiesWidgetBase +{ + Q_OBJECT + public: + + QgsMeshElevationPropertiesWidget( QgsMeshLayer *layer, QgsMapCanvas *canvas, QWidget *parent ); + + void syncToLayer( QgsMapLayer *layer ) override; + + public slots: + void apply() override; + + private slots: + + void onChanged(); + + private: + + QgsMeshLayer *mLayer = nullptr; + bool mBlockUpdates = false; + +}; + + +class QgsMeshElevationPropertiesWidgetFactory : public QObject, public QgsMapLayerConfigWidgetFactory +{ + Q_OBJECT + public: + explicit QgsMeshElevationPropertiesWidgetFactory( QObject *parent = nullptr ); + + QgsMapLayerConfigWidget *createWidget( QgsMapLayer *layer, QgsMapCanvas *canvas, bool dockWidget, QWidget *parent ) const override; + bool supportLayerPropertiesDialog() const override; + bool supportsStyleDock() const override; + bool supportsLayer( QgsMapLayer *layer ) const override; + QString layerPropertiesPagePositionHint() const override; +}; + + + +#endif // QGSMESHELEVATIONPROPERTIESWIDGET_H diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index bfaae3b6f87..913a1f2efe0 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -120,6 +120,7 @@ #include "raster/qgsrasterelevationpropertieswidget.h" #include "vector/qgsvectorelevationpropertieswidget.h" +#include "mesh/qgsmeshelevationpropertieswidget.h" #ifdef HAVE_3D #include "qgs3d.h" @@ -1487,6 +1488,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipBadLayers registerMapLayerPropertiesFactory( new QgsPointCloudElevationPropertiesWidgetFactory( this ) ); registerMapLayerPropertiesFactory( new QgsRasterElevationPropertiesWidgetFactory( this ) ); registerMapLayerPropertiesFactory( new QgsVectorElevationPropertiesWidgetFactory( this ) ); + registerMapLayerPropertiesFactory( new QgsMeshElevationPropertiesWidgetFactory( this ) ); registerMapLayerPropertiesFactory( new QgsAnnotationItemPropertiesWidgetFactory( this ) ); registerMapLayerPropertiesFactory( new QgsLayerTreeGroupPropertiesWidgetFactory( this ) ); diff --git a/src/app/raster/qgsrasterelevationpropertieswidget.cpp b/src/app/raster/qgsrasterelevationpropertieswidget.cpp index 81a19a7b201..54484083636 100644 --- a/src/app/raster/qgsrasterelevationpropertieswidget.cpp +++ b/src/app/raster/qgsrasterelevationpropertieswidget.cpp @@ -19,6 +19,7 @@ #include "qgsmaplayer.h" #include "qgsrasterlayer.h" #include "qgsrasterlayerelevationproperties.h" +#include "qgslinesymbol.h" QgsRasterElevationPropertiesWidget::QgsRasterElevationPropertiesWidget( QgsRasterLayer *layer, QgsMapCanvas *canvas, QWidget *parent ) : QgsMapLayerConfigWidget( layer, canvas, parent ) @@ -28,12 +29,14 @@ QgsRasterElevationPropertiesWidget::QgsRasterElevationPropertiesWidget( QgsRaste mOffsetZSpinBox->setClearValue( 0 ); mScaleZSpinBox->setClearValue( 1 ); mElevationGroupBox->setChecked( false ); + mLineStyleButton->setSymbolType( Qgis::SymbolType::Line ); syncToLayer( layer ); connect( mOffsetZSpinBox, qOverload( &QDoubleSpinBox::valueChanged ), this, &QgsRasterElevationPropertiesWidget::onChanged ); connect( mScaleZSpinBox, qOverload( &QDoubleSpinBox::valueChanged ), this, &QgsRasterElevationPropertiesWidget::onChanged ); connect( mElevationGroupBox, &QGroupBox::toggled, this, &QgsRasterElevationPropertiesWidget::onChanged ); + connect( mLineStyleButton, &QgsSymbolButton::changed, this, &QgsRasterElevationPropertiesWidget::onChanged ); } void QgsRasterElevationPropertiesWidget::syncToLayer( QgsMapLayer *layer ) @@ -47,6 +50,8 @@ void QgsRasterElevationPropertiesWidget::syncToLayer( QgsMapLayer *layer ) mElevationGroupBox->setChecked( props->isEnabled() ); mOffsetZSpinBox->setValue( props->zOffset() ); mScaleZSpinBox->setValue( props->zScale() ); + mLineStyleButton->setSymbol( props->profileLineSymbol()->clone() ); + mBlockUpdates = false; } @@ -59,6 +64,7 @@ void QgsRasterElevationPropertiesWidget::apply() props->setEnabled( mElevationGroupBox->isChecked() ); props->setZOffset( mOffsetZSpinBox->value() ); props->setZScale( mScaleZSpinBox->value() ); + props->setProfileLineSymbol( mLineStyleButton->clonedSymbol< QgsLineSymbol >() ); mLayer->trigger3DUpdate(); } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b8cb5d7f1a8..a2a28951dae 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -705,6 +705,7 @@ set(QGIS_CORE_SRCS mesh/qgsmeshdataset.cpp mesh/qgsmeshdatasetgroupstore.cpp mesh/qgsmeshlayer.cpp + mesh/qgsmeshlayerelevationproperties.cpp mesh/qgsmeshlayerinterpolator.cpp mesh/qgsmeshlayerprofilegenerator.cpp mesh/qgsmeshlayerrenderer.cpp @@ -1477,6 +1478,7 @@ set(QGIS_CORE_HDRS mesh/qgsmeshdataset.h mesh/qgsmeshdatasetgroupstore.h mesh/qgsmeshlayer.h + mesh/qgsmeshlayerelevationproperties.h mesh/qgsmeshlayerinterpolator.h mesh/qgsmeshlayerprofilegenerator.h mesh/qgsmeshlayerrenderer.h diff --git a/src/core/mesh/qgsmeshlayer.cpp b/src/core/mesh/qgsmeshlayer.cpp index e45a969a2b2..2da599addf6 100644 --- a/src/core/mesh/qgsmeshlayer.cpp +++ b/src/core/mesh/qgsmeshlayer.cpp @@ -44,14 +44,16 @@ #include "qgsmessagelog.h" #include "qgsexpressioncontextutils.h" #include "qgsmeshlayerprofilegenerator.h" +#include "qgsmeshlayerelevationproperties.h" QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath, const QString &baseName, const QString &providerKey, const QgsMeshLayer::LayerOptions &options ) - : QgsMapLayer( QgsMapLayerType::MeshLayer, baseName, meshLayerPath ), - mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) ), - mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) ) + : QgsMapLayer( QgsMapLayerType::MeshLayer, baseName, meshLayerPath ) + , mDatasetGroupStore( new QgsMeshDatasetGroupStore( this ) ) + , mTemporalProperties( new QgsMeshLayerTemporalProperties( this ) ) + , mElevationProperties( new QgsMeshLayerElevationProperties( this ) ) { mShouldValidateCrs = !options.skipCrsValidation; @@ -1805,3 +1807,8 @@ QgsMapLayerTemporalProperties *QgsMeshLayer::temporalProperties() { return mTemporalProperties; } + +QgsMapLayerElevationProperties *QgsMeshLayer::elevationProperties() +{ + return mElevationProperties; +} diff --git a/src/core/mesh/qgsmeshlayer.h b/src/core/mesh/qgsmeshlayer.h index 7db1008aacb..ce0445515ca 100644 --- a/src/core/mesh/qgsmeshlayer.h +++ b/src/core/mesh/qgsmeshlayer.h @@ -40,6 +40,7 @@ class QgsMesh3dAveragingMethod; class QgsMeshLayerTemporalProperties; class QgsMeshDatasetGroupStore; class QgsMeshEditor; +class QgsMeshLayerElevationProperties; /** * \ingroup core @@ -188,6 +189,7 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer, public QgsAbstractProfileSo bool readXml( const QDomNode &layer_node, QgsReadWriteContext &context ) override; bool writeXml( QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context ) const override; QgsMapLayerTemporalProperties *temporalProperties() override; + QgsMapLayerElevationProperties *elevationProperties() override; void reload() override; QStringList subLayers() const override; QString htmlMetadata() const override; @@ -958,6 +960,7 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer, public QgsAbstractProfileSo QgsMeshSimplificationSettings mSimplificationSettings; QgsMeshLayerTemporalProperties *mTemporalProperties = nullptr; + QgsMeshLayerElevationProperties *mElevationProperties = nullptr; //! Temporal unit used by the provider QgsUnitTypes::TemporalUnit mTemporalUnit = QgsUnitTypes::TemporalHours; diff --git a/src/core/mesh/qgsmeshlayerelevationproperties.cpp b/src/core/mesh/qgsmeshlayerelevationproperties.cpp new file mode 100644 index 00000000000..4511ff5e7dc --- /dev/null +++ b/src/core/mesh/qgsmeshlayerelevationproperties.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + qgsmeshlayerelevationproperties.cpp + --------------- + begin : February 2022 + copyright : (C) 2022 by Nyall Dawson + email : nyall dot dawson dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsmeshlayerelevationproperties.h" +#include "qgsmeshlayer.h" +#include "qgslinesymbol.h" +#include "qgssymbollayerutils.h" +#include "qgslinesymbollayer.h" +#include "qgsapplication.h" +#include "qgscolorschemeregistry.h" + +QgsMeshLayerElevationProperties::QgsMeshLayerElevationProperties( QObject *parent ) + : QgsMapLayerElevationProperties( parent ) +{ + setDefaultProfileLineSymbol(); +} + +QgsMeshLayerElevationProperties::~QgsMeshLayerElevationProperties() = default; + +bool QgsMeshLayerElevationProperties::hasElevation() const +{ + return true; +} + +QDomElement QgsMeshLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) +{ + QDomElement element = document.createElement( QStringLiteral( "elevation" ) ); + element.setAttribute( QStringLiteral( "zoffset" ), qgsDoubleToString( mZOffset ) ); + element.setAttribute( QStringLiteral( "zscale" ), qgsDoubleToString( mZScale ) ); + + QDomElement profileLineSymbolElement = document.createElement( QStringLiteral( "profileLineSymbol" ) ); + profileLineSymbolElement.appendChild( QgsSymbolLayerUtils::saveSymbol( QString(), mProfileLineSymbol.get(), document, context ) ); + element.appendChild( profileLineSymbolElement ); + + parentElement.appendChild( element ); + return element; +} + +bool QgsMeshLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext &context ) +{ + const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement(); + mZOffset = elevationElement.attribute( QStringLiteral( "zoffset" ), QStringLiteral( "0" ) ).toDouble(); + mZScale = elevationElement.attribute( QStringLiteral( "zscale" ), QStringLiteral( "1" ) ).toDouble(); + + const QDomElement profileLineSymbolElement = elevationElement.firstChildElement( QStringLiteral( "profileLineSymbol" ) ).firstChildElement( QStringLiteral( "symbol" ) ); + mProfileLineSymbol.reset( QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( profileLineSymbolElement, context ) ); + if ( !mProfileLineSymbol ) + setDefaultProfileLineSymbol(); + + return true; +} + +bool QgsMeshLayerElevationProperties::isVisibleInZRange( const QgsDoubleRange & ) const +{ + // TODO -- test actual raster z range + return true; +} + +QgsDoubleRange QgsMeshLayerElevationProperties::calculateZRange( QgsMapLayer * ) const +{ + // TODO -- determine actual z range from raster statistics + return QgsDoubleRange(); +} + +QgsLineSymbol *QgsMeshLayerElevationProperties::profileLineSymbol() const +{ + return mProfileLineSymbol.get(); +} + +void QgsMeshLayerElevationProperties::setProfileLineSymbol( QgsLineSymbol *symbol ) +{ + mProfileLineSymbol.reset( symbol ); +} + +void QgsMeshLayerElevationProperties::setDefaultProfileLineSymbol() +{ + std::unique_ptr< QgsSimpleLineSymbolLayer > profileLineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor(), 0.6 ); + mProfileLineSymbol = std::make_unique< QgsLineSymbol>( QgsSymbolLayerList( { profileLineLayer.release() } ) ); +} diff --git a/src/core/mesh/qgsmeshlayerelevationproperties.h b/src/core/mesh/qgsmeshlayerelevationproperties.h new file mode 100644 index 00000000000..6ddf97251e7 --- /dev/null +++ b/src/core/mesh/qgsmeshlayerelevationproperties.h @@ -0,0 +1,78 @@ +/*************************************************************************** + qgsmeshlayerelevationproperties.h + --------------- + begin : February 2022 + copyright : (C) 2022 by Nyall Dawson + email : nyall dot dawson dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + + +#ifndef QGSMESHLAYERELEVATIONPROPERTIES_H +#define QGSMESHLAYERELEVATIONPROPERTIES_H + +#include "qgis_core.h" +#include "qgis_sip.h" +#include "qgsmaplayerelevationproperties.h" + +class QgsLineSymbol; + +/** + * \class QgsMeshLayerElevationProperties + * \ingroup core + * \brief Mesh layer specific subclass of QgsMapLayerElevationProperties. + * + * \since QGIS 3.26 + */ +class CORE_EXPORT QgsMeshLayerElevationProperties : public QgsMapLayerElevationProperties +{ + + Q_OBJECT + + public: + + /** + * Constructor for QgsMeshLayerElevationProperties, with the specified \a parent object. + */ + QgsMeshLayerElevationProperties( QObject *parent SIP_TRANSFERTHIS ); + ~QgsMeshLayerElevationProperties() override; + + bool hasElevation() const override; + QDomElement writeXml( QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context ) override; + bool readXml( const QDomElement &element, const QgsReadWriteContext &context ) override; + bool isVisibleInZRange( const QgsDoubleRange &range ) const override; + QgsDoubleRange calculateZRange( QgsMapLayer *layer ) const override; + + /** + * Returns the line symbol used to render the mesh profile in elevation profile plots. + * + * \see setProfileLineSymbol() + */ + QgsLineSymbol *profileLineSymbol() const; + + /** + * Sets the line \a symbol used to render the mesh profile in elevation profile plots. + * + * Ownership of \a symbol is transferred to the plot. + * + * \see profileLineSymbol() + */ + void setProfileLineSymbol( QgsLineSymbol *symbol SIP_TRANSFER ); + + private: + + void setDefaultProfileLineSymbol(); + + std::unique_ptr< QgsLineSymbol > mProfileLineSymbol; + +}; + +#endif // QGSMESHLAYERELEVATIONPROPERTIES_H diff --git a/src/core/qgsmaplayerelevationproperties.h b/src/core/qgsmaplayerelevationproperties.h index 6b6370bbe13..3d77a96d478 100644 --- a/src/core/qgsmaplayerelevationproperties.h +++ b/src/core/qgsmaplayerelevationproperties.h @@ -43,6 +43,7 @@ class CORE_EXPORT QgsMapLayerElevationProperties : public QObject #include "qgspointcloudlayerelevationproperties.h" #include "qgsrasterlayerelevationproperties.h" #include "qgsvectorlayerelevationproperties.h" +#include "qgsmeshlayerelevationproperties.h" #endif Q_OBJECT @@ -61,6 +62,10 @@ class CORE_EXPORT QgsMapLayerElevationProperties : public QObject { sipType = sipType_QgsRasterLayerElevationProperties; } + else if ( qobject_cast( sipCpp ) ) + { + sipType = sipType_QgsMeshLayerElevationProperties; + } else { sipType = 0; diff --git a/src/core/raster/qgsrasterlayerprofilegenerator.cpp b/src/core/raster/qgsrasterlayerprofilegenerator.cpp index 95e413a67b8..455564dba5e 100644 --- a/src/core/raster/qgsrasterlayerprofilegenerator.cpp +++ b/src/core/raster/qgsrasterlayerprofilegenerator.cpp @@ -22,6 +22,7 @@ #include "qgsrasteriterator.h" #include "qgsgeometryengine.h" #include "qgsgeos.h" +#include "qgslinesymbol.h" #include "qgsapplication.h" #include "qgscolorschemeregistry.h" diff --git a/src/ui/mesh/qgsmeshelevationpropertieswidgetbase.ui b/src/ui/mesh/qgsmeshelevationpropertieswidgetbase.ui new file mode 100644 index 00000000000..40ca1f6d2b5 --- /dev/null +++ b/src/ui/mesh/qgsmeshelevationpropertieswidgetbase.ui @@ -0,0 +1,163 @@ + + + QgsMeshElevationPropertiesWidgetBase + + + + 0 + 0 + 592 + 447 + + + + Raster Elevation Properties + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::StrongFocus + + + Elevation Surface + + + false + + + vectorgeneral + + + + + + 6 + + + -99999999999.000000000000000 + + + 99999999999.000000000000000 + + + + + + + Offset + + + + + + + Scale + + + + + + + 6 + + + 0.000000000000000 + + + 99999999999.000000000000000 + + + 1.000000000000000 + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Elevation scaling and offset can be used to manually correct elevation values from the layer.</span></p><p>The scale is applied to the mesh values before adding the offset.</p></body></html> + + + true + + + + + + + + + + Profile Chart Appearance + + + + + + Line style + + + + + + + + 0 + 0 + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QgsDoubleSpinBox + QDoubleSpinBox +
qgsdoublespinbox.h
+
+ + QgsSymbolButton + QToolButton +
qgssymbolbutton.h
+
+
+ + mElevationGroupBox + mScaleZSpinBox + mOffsetZSpinBox + + + +
diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt index e9ba1968472..54c9c84766a 100644 --- a/tests/src/python/CMakeLists.txt +++ b/tests/src/python/CMakeLists.txt @@ -209,6 +209,7 @@ ADD_PYTHON_TEST(PyQgsMapUnitScale test_qgsmapunitscale.py) ADD_PYTHON_TEST(PyQgsMargins test_qgsmargins.py) ADD_PYTHON_TEST(PyQgsMarkerLineSymbolLayer test_qgsmarkerlinesymbollayer.py) ADD_PYTHON_TEST(PyQgsMergedFeatureRenderer test_qgsmergedfeaturerenderer.py) +ADD_PYTHON_TEST(PyQgsMeshLayerElevationProperties test_qgsmeshlayerelevationproperties.py) ADD_PYTHON_TEST(PyQgsMessageLog test_qgsmessagelog.py) ADD_PYTHON_TEST(PyQgsMetadataBase test_qgsmetadatabase.py) ADD_PYTHON_TEST(PyQgsMetadataUtils test_qgsmetadatautils.py) diff --git a/tests/src/python/test_qgsmeshlayerelevationproperties.py b/tests/src/python/test_qgsmeshlayerelevationproperties.py new file mode 100644 index 00000000000..d39f4d40c65 --- /dev/null +++ b/tests/src/python/test_qgsmeshlayerelevationproperties.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +"""QGIS Unit tests for QgsMeshLayerElevationProperties + +.. note:: 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__ = 'Nyall Dawson' +__date__ = '09/11/2020' +__copyright__ = 'Copyright 2020, The QGIS Project' + +import qgis # NOQA + +from qgis.core import ( + QgsMeshLayerElevationProperties, + QgsReadWriteContext, + QgsLineSymbol +) + +from qgis.PyQt.QtXml import QDomDocument + +from qgis.testing import start_app, unittest + +start_app() + + +class TestQgsMeshLayerElevationProperties(unittest.TestCase): + + def testBasic(self): + props = QgsMeshLayerElevationProperties(None) + self.assertEqual(props.zScale(), 1) + self.assertEqual(props.zOffset(), 0) + self.assertTrue(props.hasElevation()) + self.assertIsInstance(props.profileLineSymbol(), QgsLineSymbol) + + props.setZOffset(0.5) + props.setZScale(2) + self.assertEqual(props.zScale(), 2) + self.assertEqual(props.zOffset(), 0.5) + self.assertTrue(props.hasElevation()) + + sym = QgsLineSymbol.createSimple({'outline_color': '#ff4433', 'outline_width': 0.5}) + props.setProfileLineSymbol(sym) + self.assertEqual(props.profileLineSymbol().color().name(), '#ff4433') + + doc = QDomDocument("testdoc") + elem = doc.createElement('test') + props.writeXml(elem, doc, QgsReadWriteContext()) + + props2 = QgsMeshLayerElevationProperties(None) + props2.readXml(elem, QgsReadWriteContext()) + self.assertEqual(props2.zScale(), 2) + self.assertEqual(props2.zOffset(), 0.5) + self.assertEqual(props2.profileLineSymbol().color().name(), '#ff4433') + + +if __name__ == '__main__': + unittest.main()