Add QgsMapLayerElevationProperties subclass for raster layers

Allows elevation properties to be set for raster layers, including:

- whether raster values represent heights
- scale
- offset

These properties can be set through the new "Elevation" tab in
the raster layer properties dialog
This commit is contained in:
Nyall Dawson 2022-02-23 13:32:59 +10:00
parent 1bd6c4535a
commit 2379de4a95
17 changed files with 681 additions and 1 deletions

View File

@ -25,12 +25,17 @@ how an individual :py:class:`QgsMapLayer` behaves with relation to z values or e
%TypeHeaderCode
#include "qgsmaplayerelevationproperties.h"
#include "qgspointcloudlayerelevationproperties.h"
#include "qgsrasterlayerelevationproperties.h"
%End
%ConvertToSubClassCode
if ( qobject_cast<QgsPointCloudLayerElevationProperties *>( sipCpp ) )
{
sipType = sipType_QgsPointCloudLayerElevationProperties;
}
else if ( qobject_cast<QgsRasterLayerElevationProperties *>( sipCpp ) )
{
sipType = sipType_QgsRasterLayerElevationProperties;
}
else
{
sipType = 0;

View File

@ -421,6 +421,8 @@ to be drawn outside the data extent.
virtual QgsMapLayerTemporalProperties *temporalProperties();
virtual QgsMapLayerElevationProperties *elevationProperties();
public slots:
void showStatusMessage( const QString &message );

View File

@ -0,0 +1,112 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/raster/qgsrasterlayerelevationproperties.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsRasterLayerElevationProperties : QgsMapLayerElevationProperties
{
%Docstring(signature="appended")
Raster layer specific subclass of :py:class:`QgsMapLayerElevationProperties`.
.. versionadded:: 3.26
%End
%TypeHeaderCode
#include "qgsrasterlayerelevationproperties.h"
%End
public:
QgsRasterLayerElevationProperties( QObject *parent /TransferThis/ );
%Docstring
Constructor for QgsRasterLayerElevationProperties, with the specified ``parent`` object.
%End
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;
bool isEnabled() const;
%Docstring
Returns ``True`` if the elevation properties are enabled, i.e. the raster layer values represent an elevation surface.
.. seealso:: :py:func:`setEnabled`
%End
void setEnabled( bool enabled );
%Docstring
Sets whether the elevation properties are enabled, i.e. the raster layer values represent an elevation surface.
.. seealso:: :py:func:`isEnabled`
%End
double zOffset() const;
%Docstring
Returns the z offset, which is a fixed offset amount which should be added to z values from
the layer.
.. note::
Any scaling specified via :py:func:`~QgsRasterLayerElevationProperties.zScale` is applied before any offset value specified via :py:func:`~QgsRasterLayerElevationProperties.zOffset`
.. seealso:: :py:func:`setZOffset`
%End
void setZOffset( double offset );
%Docstring
Sets the z ``offset``, which is a fixed offset amount which will be added to z values from
the layer.
.. note::
Any scaling specified via :py:func:`~QgsRasterLayerElevationProperties.zScale` is applied before any offset value specified via :py:func:`~QgsRasterLayerElevationProperties.zOffset`
.. seealso:: :py:func:`zOffset`
%End
double zScale() const;
%Docstring
Returns the z scale, which is a scaling factor which should be applied to z values from
the layer.
.. note::
Any scaling specified via :py:func:`~QgsRasterLayerElevationProperties.zScale` is applied before any offset value specified via :py:func:`~QgsRasterLayerElevationProperties.zOffset`
.. seealso:: :py:func:`setZScale`
%End
void setZScale( double scale );
%Docstring
Sets the z ``scale``, which is a scaling factor which will be applied to z values from
the layer.
.. note::
Any scaling specified via :py:func:`~QgsRasterLayerElevationProperties.zScale` is applied before any offset value specified via :py:func:`~QgsRasterLayerElevationProperties.zOffset`
.. seealso:: :py:func:`zScale`
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/raster/qgsrasterlayerelevationproperties.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -577,6 +577,7 @@
%Include auto_generated/raster/qgsrasterinterface.sip
%Include auto_generated/raster/qgsrasteriterator.sip
%Include auto_generated/raster/qgsrasterlayer.sip
%Include auto_generated/raster/qgsrasterlayerelevationproperties.sip
%Include auto_generated/raster/qgsrasterlayertemporalproperties.sip
%Include auto_generated/raster/qgsrasterminmaxorigin.sip
%Include auto_generated/raster/qgsrasternuller.sip

View File

@ -130,6 +130,8 @@ set(QGIS_APP_SRCS
pointcloud/qgspointcloudlayerproperties.cpp
pointcloud/qgspointcloudlayerstylewidget.cpp
raster/qgsrasterelevationpropertieswidget.cpp
vectortile/qgsvectortilelayerproperties.cpp
vertextool/qgslockedfeature.cpp

View File

@ -117,6 +117,8 @@
#include "options/qgsgpsdeviceoptions.h"
#include "options/qgscustomprojectionoptions.h"
#include "raster/qgsrasterelevationpropertieswidget.h"
#ifdef HAVE_3D
#include "qgs3d.h"
#include "qgs3danimationsettings.h"
@ -1478,6 +1480,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipBadLayers
registerMapLayerPropertiesFactory( new QgsPointCloudLayer3DRendererWidgetFactory( this ) );
#endif
registerMapLayerPropertiesFactory( new QgsPointCloudElevationPropertiesWidgetFactory( this ) );
registerMapLayerPropertiesFactory( new QgsRasterElevationPropertiesWidgetFactory( this ) );
registerMapLayerPropertiesFactory( new QgsAnnotationItemPropertiesWidgetFactory( this ) );
registerMapLayerPropertiesFactory( new QgsLayerTreeGroupPropertiesWidgetFactory( this ) );

View File

@ -0,0 +1,107 @@
/***************************************************************************
qgsrasterelevationpropertieswidget.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 "qgsrasterelevationpropertieswidget.h"
#include "qgsstyle.h"
#include "qgsapplication.h"
#include "qgsmaplayer.h"
#include "qgsrasterlayer.h"
#include "qgsrasterlayerelevationproperties.h"
QgsRasterElevationPropertiesWidget::QgsRasterElevationPropertiesWidget( QgsRasterLayer *layer, QgsMapCanvas *canvas, QWidget *parent )
: QgsMapLayerConfigWidget( layer, canvas, parent )
{
setupUi( this );
mOffsetZSpinBox->setClearValue( 0 );
mScaleZSpinBox->setClearValue( 1 );
mElevationGroupBox->setChecked( false );
syncToLayer( layer );
connect( mOffsetZSpinBox, qOverload<double >( &QDoubleSpinBox::valueChanged ), this, &QgsRasterElevationPropertiesWidget::onChanged );
connect( mScaleZSpinBox, qOverload<double >( &QDoubleSpinBox::valueChanged ), this, &QgsRasterElevationPropertiesWidget::onChanged );
connect( mElevationGroupBox, &QGroupBox::toggled, this, &QgsRasterElevationPropertiesWidget::onChanged );
}
void QgsRasterElevationPropertiesWidget::syncToLayer( QgsMapLayer *layer )
{
mLayer = qobject_cast< QgsRasterLayer * >( layer );
if ( !mLayer )
return;
mBlockUpdates = true;
const QgsRasterLayerElevationProperties *props = qgis::down_cast< const QgsRasterLayerElevationProperties * >( mLayer->elevationProperties() );
mElevationGroupBox->setChecked( props->isEnabled() );
mOffsetZSpinBox->setValue( props->zOffset() );
mScaleZSpinBox->setValue( props->zScale() );
mBlockUpdates = false;
}
void QgsRasterElevationPropertiesWidget::apply()
{
if ( !mLayer )
return;
QgsRasterLayerElevationProperties *props = qgis::down_cast< QgsRasterLayerElevationProperties * >( mLayer->elevationProperties() );
props->setEnabled( mElevationGroupBox->isChecked() );
props->setZOffset( mOffsetZSpinBox->value() );
props->setZScale( mScaleZSpinBox->value() );
mLayer->trigger3DUpdate();
}
void QgsRasterElevationPropertiesWidget::onChanged()
{
if ( !mBlockUpdates )
emit widgetChanged();
}
//
// QgsRasterElevationPropertiesWidgetFactory
//
QgsRasterElevationPropertiesWidgetFactory::QgsRasterElevationPropertiesWidgetFactory( QObject *parent )
: QObject( parent )
{
setIcon( QgsApplication::getThemeIcon( QStringLiteral( "propertyicons/elevationscale.svg" ) ) );
setTitle( tr( "Elevation" ) );
}
QgsMapLayerConfigWidget *QgsRasterElevationPropertiesWidgetFactory::createWidget( QgsMapLayer *layer, QgsMapCanvas *canvas, bool, QWidget *parent ) const
{
return new QgsRasterElevationPropertiesWidget( qobject_cast< QgsRasterLayer * >( layer ), canvas, parent );
}
bool QgsRasterElevationPropertiesWidgetFactory::supportLayerPropertiesDialog() const
{
return true;
}
bool QgsRasterElevationPropertiesWidgetFactory::supportsStyleDock() const
{
return true;
}
bool QgsRasterElevationPropertiesWidgetFactory::supportsLayer( QgsMapLayer *layer ) const
{
return layer->type() == QgsMapLayerType::RasterLayer;
}
QString QgsRasterElevationPropertiesWidgetFactory::layerPropertiesPagePositionHint() const
{
return QStringLiteral( "mOptsPage_Metadata" );
}

View File

@ -0,0 +1,65 @@
/***************************************************************************
qgsrasterelevationpropertieswidget.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 QGSRASTERELEVATIONPROPERTIESWIDGET_H
#define QGSRASTERELEVATIONPROPERTIESWIDGET_H
#include "qgsmaplayerconfigwidget.h"
#include "qgsmaplayerconfigwidgetfactory.h"
#include "ui_qgsrasterelevationpropertieswidgetbase.h"
class QgsRasterLayer;
class QgsRasterElevationPropertiesWidget : public QgsMapLayerConfigWidget, private Ui::QgsRasterElevationPropertiesWidgetBase
{
Q_OBJECT
public:
QgsRasterElevationPropertiesWidget( QgsRasterLayer *layer, QgsMapCanvas *canvas, QWidget *parent );
void syncToLayer( QgsMapLayer *layer ) override;
public slots:
void apply() override;
private slots:
void onChanged();
private:
QgsRasterLayer *mLayer = nullptr;
bool mBlockUpdates = false;
};
class QgsRasterElevationPropertiesWidgetFactory : public QObject, public QgsMapLayerConfigWidgetFactory
{
Q_OBJECT
public:
explicit QgsRasterElevationPropertiesWidgetFactory( 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 // QGSRASTERELEVATIONPROPERTIESWIDGET_H

View File

@ -657,6 +657,7 @@ set(QGIS_CORE_SRCS
raster/qgsrasterinterface.cpp
raster/qgsrasteriterator.cpp
raster/qgsrasterlayer.cpp
raster/qgsrasterlayerelevationproperties.cpp
raster/qgsrasterlayerrenderer.cpp
raster/qgsrasterlayertemporalproperties.cpp
raster/qgsrasterminmaxorigin.cpp
@ -1648,6 +1649,7 @@ set(QGIS_CORE_HDRS
raster/qgsrasterinterface.h
raster/qgsrasteriterator.h
raster/qgsrasterlayer.h
raster/qgsrasterlayerelevationproperties.h
raster/qgsrasterlayerrenderer.h
raster/qgsrasterlayertemporalproperties.h
raster/qgsrasterminmaxorigin.h

View File

@ -41,6 +41,7 @@ class CORE_EXPORT QgsMapLayerElevationProperties : public QObject
{
#ifdef SIP_RUN
#include "qgspointcloudlayerelevationproperties.h"
#include "qgsrasterlayerelevationproperties.h"
#endif
Q_OBJECT
@ -51,6 +52,10 @@ class CORE_EXPORT QgsMapLayerElevationProperties : public QObject
{
sipType = sipType_QgsPointCloudLayerElevationProperties;
}
else if ( qobject_cast<QgsRasterLayerElevationProperties *>( sipCpp ) )
{
sipType = sipType_QgsRasterLayerElevationProperties;
}
else
{
sipType = 0;

View File

@ -59,6 +59,7 @@ email : tim at linfiniti.com
#include "qgsruntimeprofiler.h"
#include "qgsmaplayerfactory.h"
#include "qgsrasterpipe.h"
#include "qgsrasterlayerelevationproperties.h"
#include <cmath>
#include <cstdio>
@ -107,8 +108,8 @@ QgsRasterLayer::QgsRasterLayer()
, QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
, TRSTRING_NOT_SET( tr( "Not Set" ) )
, mTemporalProperties( new QgsRasterLayerTemporalProperties( this ) )
, mElevationProperties( new QgsRasterLayerElevationProperties( this ) )
, mPipe( std::make_unique< QgsRasterPipe >() )
{
init();
setValid( false );
@ -123,6 +124,7 @@ QgsRasterLayer::QgsRasterLayer( const QString &uri,
, QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
, TRSTRING_NOT_SET( tr( "Not Set" ) )
, mTemporalProperties( new QgsRasterLayerTemporalProperties( this ) )
, mElevationProperties( new QgsRasterLayerElevationProperties( this ) )
, mPipe( std::make_unique< QgsRasterPipe >() )
{
mShouldValidateCrs = !options.skipCrsValidation;
@ -1070,6 +1072,11 @@ QgsMapLayerTemporalProperties *QgsRasterLayer::temporalProperties()
return mTemporalProperties;
}
QgsMapLayerElevationProperties *QgsRasterLayer::elevationProperties()
{
return mElevationProperties;
}
void QgsRasterLayer::setContrastEnhancement( QgsContrastEnhancement::ContrastEnhancementAlgorithm algorithm, QgsRasterMinMaxOrigin::Limits limits, const QgsRectangle &extent, int sampleSize, bool generateLookupTableFlag )
{
setContrastEnhancement( algorithm,

View File

@ -47,6 +47,7 @@ class QgsRasterPipe;
class QgsRasterResampleFilter;
class QgsBrightnessContrastFilter;
class QgsHueSaturationFilter;
class QgsRasterLayerElevationProperties;
class QImage;
class QPixmap;
@ -467,6 +468,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
bool ignoreExtents() const;
QgsMapLayerTemporalProperties *temporalProperties() override;
QgsMapLayerElevationProperties *elevationProperties() override;
public slots:
void showStatusMessage( const QString &message );
@ -552,6 +554,8 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
//! Pointer to temporal properties
QgsRasterLayerTemporalProperties *mTemporalProperties = nullptr;
QgsRasterLayerElevationProperties *mElevationProperties = nullptr;
//! [ data provider interface ] Timestamp, the last modified time of the data source when the layer was created
QDateTime mLastModified;

View File

@ -0,0 +1,60 @@
/***************************************************************************
qgsrasterlayerelevationproperties.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 "qgsrasterlayerelevationproperties.h"
#include "qgsrasterlayer.h"
QgsRasterLayerElevationProperties::QgsRasterLayerElevationProperties( QObject *parent )
: QgsMapLayerElevationProperties( parent )
{
}
bool QgsRasterLayerElevationProperties::hasElevation() const
{
return mEnabled;
}
QDomElement QgsRasterLayerElevationProperties::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext & )
{
QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
element.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
element.setAttribute( QStringLiteral( "zoffset" ), qgsDoubleToString( mZOffset ) );
element.setAttribute( QStringLiteral( "zscale" ), qgsDoubleToString( mZScale ) );
parentElement.appendChild( element );
return element;
}
bool QgsRasterLayerElevationProperties::readXml( const QDomElement &element, const QgsReadWriteContext & )
{
const QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
mEnabled = elevationElement.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt();
mZOffset = elevationElement.attribute( QStringLiteral( "zoffset" ), QStringLiteral( "0" ) ).toDouble();
mZScale = elevationElement.attribute( QStringLiteral( "zscale" ), QStringLiteral( "1" ) ).toDouble();
return true;
}
bool QgsRasterLayerElevationProperties::isVisibleInZRange( const QgsDoubleRange & ) const
{
// TODO -- test actual raster z range
return true;
}
QgsDoubleRange QgsRasterLayerElevationProperties::calculateZRange( QgsMapLayer * ) const
{
// TODO -- determine actual z range from raster statistics
return QgsDoubleRange();
}

View File

@ -0,0 +1,112 @@
/***************************************************************************
qgsrasterlayerelevationproperties.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 QGSRASTERLAYERELEVATIONPROPERTIES_H
#define QGSRASTERLAYERELEVATIONPROPERTIES_H
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgsmaplayerelevationproperties.h"
/**
* \class QgsRasterLayerElevationProperties
* \ingroup core
* \brief Raster layer specific subclass of QgsMapLayerElevationProperties.
*
* \since QGIS 3.26
*/
class CORE_EXPORT QgsRasterLayerElevationProperties : public QgsMapLayerElevationProperties
{
Q_OBJECT
public:
/**
* Constructor for QgsRasterLayerElevationProperties, with the specified \a parent object.
*/
QgsRasterLayerElevationProperties( QObject *parent SIP_TRANSFERTHIS );
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 TRUE if the elevation properties are enabled, i.e. the raster layer values represent an elevation surface.
*
* \see setEnabled()
*/
bool isEnabled() const { return mEnabled; }
/**
* Sets whether the elevation properties are enabled, i.e. the raster layer values represent an elevation surface.
*
* \see isEnabled()
*/
void setEnabled( bool enabled ) { mEnabled = enabled; }
/**
* Returns the z offset, which is a fixed offset amount which should be added to z values from
* the layer.
*
* \note Any scaling specified via zScale() is applied before any offset value specified via zOffset()
*
* \see setZOffset()
*/
double zOffset() const { return mZOffset; }
/**
* Sets the z \a offset, which is a fixed offset amount which will be added to z values from
* the layer.
*
* \note Any scaling specified via zScale() is applied before any offset value specified via zOffset()
*
* \see zOffset()
*/
void setZOffset( double offset ) { mZOffset = offset; }
/**
* Returns the z scale, which is a scaling factor which should be applied to z values from
* the layer.
*
* \note Any scaling specified via zScale() is applied before any offset value specified via zOffset()
*
* \see setZScale()
*/
double zScale() const { return mZScale; }
/**
* Sets the z \a scale, which is a scaling factor which will be applied to z values from
* the layer.
*
* \note Any scaling specified via zScale() is applied before any offset value specified via zOffset()
*
* \see zScale()
*/
void setZScale( double scale ) { mZScale = scale; }
private:
bool mEnabled = false;
double mZScale = 1.0;
double mZOffset = 0.0;
};
#endif // QGSRASTERLAYERELEVATIONPROPERTIES_H

View File

@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsRasterElevationPropertiesWidgetBase</class>
<widget class="QWidget" name="QgsRasterElevationPropertiesWidgetBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>242</height>
</rect>
</property>
<property name="windowTitle">
<string>Raster Elevation Properties</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="mElevationGroupBox">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="title">
<string>Represents Elevation Surface</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="syncGroup" stdset="0">
<string notr="true">vectorgeneral</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="0">
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Offset</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Scale</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Elevation scaling and offset can be used to manually correct elevation values from the layer.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;The scale is applied to the raster values before adding the offset.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QgsDoubleSpinBox" name="mScaleZSpinBox">
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>99999999999.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QgsDoubleSpinBox" name="mOffsetZSpinBox">
<property name="decimals">
<number>6</number>
</property>
<property name="minimum">
<double>-99999999999.000000000000000</double>
</property>
<property name="maximum">
<double>99999999999.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>qgsdoublespinbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mElevationGroupBox</tabstop>
<tabstop>mScaleZSpinBox</tabstop>
<tabstop>mOffsetZSpinBox</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -272,6 +272,7 @@ ADD_PYTHON_TEST(PyQgsRasterBandComboBox test_qgsrasterbandcombobox.py)
ADD_PYTHON_TEST(PyQgsRasterFileWriter test_qgsrasterfilewriter.py)
ADD_PYTHON_TEST(PyQgsRasterFileWriterTask test_qgsrasterfilewritertask.py)
ADD_PYTHON_TEST(PyQgsRasterLayer test_qgsrasterlayer.py)
ADD_PYTHON_TEST(PyQgsRasterLayerElevationProperties test_qgsrasterlayerelevationproperties.py)
ADD_PYTHON_TEST(PyQgsRasterLayerProperties test_qgsrasterlayerproperties.py)
ADD_PYTHON_TEST(PyQgsRasterLayerRenderer test_qgsrasterlayerrenderer.py)
ADD_PYTHON_TEST(PyQgsRasterColorRampShader test_qgsrastercolorrampshader.py)

View File

@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsRasterLayerElevationProperties
.. 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 (
QgsRasterLayerElevationProperties,
QgsReadWriteContext,
)
from qgis.PyQt.QtXml import QDomDocument
from qgis.testing import start_app, unittest
start_app()
class TestQgsRasterLayerElevationProperties(unittest.TestCase):
def testBasic(self):
props = QgsRasterLayerElevationProperties(None)
self.assertEqual(props.zScale(), 1)
self.assertEqual(props.zOffset(), 0)
self.assertFalse(props.isEnabled())
self.assertFalse(props.hasElevation())
props.setZOffset(0.5)
props.setZScale(2)
props.setEnabled(True)
self.assertEqual(props.zScale(), 2)
self.assertEqual(props.zOffset(), 0.5)
self.assertTrue(props.isEnabled())
self.assertTrue(props.hasElevation())
doc = QDomDocument("testdoc")
elem = doc.createElement('test')
props.writeXml(elem, doc, QgsReadWriteContext())
props2 = QgsRasterLayerElevationProperties(None)
props2.readXml(elem, QgsReadWriteContext())
self.assertEqual(props2.zScale(), 2)
self.assertEqual(props2.zOffset(), 0.5)
self.assertTrue(props.isEnabled())
if __name__ == '__main__':
unittest.main()