diff --git a/python/core/auto_generated/pointcloud/qgspointcloudrenderer.sip.in b/python/core/auto_generated/pointcloud/qgspointcloudrenderer.sip.in index c041850c1b9c..0dc32e5f1621 100644 --- a/python/core/auto_generated/pointcloud/qgspointcloudrenderer.sip.in +++ b/python/core/auto_generated/pointcloud/qgspointcloudrenderer.sip.in @@ -126,6 +126,8 @@ Abstract base class for 2d point cloud renderers. %End public: + QgsPointCloudRenderer(); + virtual ~QgsPointCloudRenderer(); virtual QString type() const = 0; @@ -139,6 +141,8 @@ Create a deep copy of this renderer. Should be implemented by all subclasses and generate a proper subclass. %End + + virtual void renderBlock( const QgsPointCloudBlock *block, QgsPointCloudRenderContext &context ) = 0; %Docstring Renders a ``block`` of point cloud data using the specified render ``context``. @@ -205,6 +209,8 @@ Calls to :py:func:`~QgsPointCloudRenderer.stopRender` must always be preceded by Retrieves the x and y coordinate for the point at index ``i``. %End + private: + QgsPointCloudRenderer( const QgsPointCloudRenderer &other ); }; /************************************************************************ diff --git a/python/core/auto_generated/pointcloud/qgspointcloudrgbrenderer.sip.in b/python/core/auto_generated/pointcloud/qgspointcloudrgbrenderer.sip.in index 142c6d91d5aa..c967042c8917 100644 --- a/python/core/auto_generated/pointcloud/qgspointcloudrgbrenderer.sip.in +++ b/python/core/auto_generated/pointcloud/qgspointcloudrgbrenderer.sip.in @@ -9,6 +9,7 @@ + class QgsPointCloudRgbRenderer : QgsPointCloudRenderer { %Docstring @@ -26,6 +27,7 @@ An RGB renderer for 2d visualisation of point clouds using embedded red, green a %Docstring Constructor for QgsPointCloudRgbRenderer. %End + virtual QString type() const; virtual QgsPointCloudRenderer *clone() const; @@ -120,6 +122,78 @@ Sets the ``attribute`` to use for the blue channel. .. seealso:: :py:func:`setGreenAttribute` .. seealso:: :py:func:`blueAttribute` +%End + + const QgsContrastEnhancement *redContrastEnhancement() const; +%Docstring +Returns the contrast enchancement to use for the red channel. + +.. seealso:: :py:func:`setRedContrastEnhancement` + +.. seealso:: :py:func:`greenContrastEnhancement` + +.. seealso:: :py:func:`blueContrastEnhancement` +%End + + void setRedContrastEnhancement( QgsContrastEnhancement *enhancement /Transfer/ ); +%Docstring +Sets the contrast ``enchancement`` to use for the red channel. + +Ownership of ``enhancement`` is transferred. + +.. seealso:: :py:func:`redContrastEnhancement` + +.. seealso:: :py:func:`setGreenContrastEnhancement` + +.. seealso:: :py:func:`setBlueContrastEnhancement` +%End + + const QgsContrastEnhancement *greenContrastEnhancement() const; +%Docstring +Returns the contrast enchancement to use for the green channel. + +.. seealso:: :py:func:`setGreenContrastEnhancement` + +.. seealso:: :py:func:`redContrastEnhancement` + +.. seealso:: :py:func:`blueContrastEnhancement` +%End + + void setGreenContrastEnhancement( QgsContrastEnhancement *enhancement /Transfer/ ); +%Docstring +Sets the contrast ``enchancement`` to use for the green channel. + +Ownership of ``enhancement`` is transferred. + +.. seealso:: :py:func:`greenContrastEnhancement` + +.. seealso:: :py:func:`setRedContrastEnhancement` + +.. seealso:: :py:func:`setBlueContrastEnhancement` +%End + + const QgsContrastEnhancement *blueContrastEnhancement() const; +%Docstring +Returns the contrast enchancement to use for the blue channel. + +.. seealso:: :py:func:`setBlueContrastEnhancement` + +.. seealso:: :py:func:`redContrastEnhancement` + +.. seealso:: :py:func:`greenContrastEnhancement` +%End + + void setBlueContrastEnhancement( QgsContrastEnhancement *enhancement /Transfer/ ); +%Docstring +Sets the contrast ``enchancement`` to use for the blue channel. + +Ownership of ``enhancement`` is transferred. + +.. seealso:: :py:func:`blueContrastEnhancement` + +.. seealso:: :py:func:`setRedContrastEnhancement` + +.. seealso:: :py:func:`setGreenContrastEnhancement` %End }; diff --git a/python/core/auto_generated/raster/qgscontrastenhancement.sip.in b/python/core/auto_generated/raster/qgscontrastenhancement.sip.in index 9e90fd16408a..77b60c5c2f5f 100644 --- a/python/core/auto_generated/raster/qgscontrastenhancement.sip.in +++ b/python/core/auto_generated/raster/qgscontrastenhancement.sip.in @@ -14,7 +14,7 @@ class QgsContrastEnhancement { %Docstring -Manipulates raster pixel values so that they enhanceContrast or clip into a +Manipulates raster or point cloud pixel values so that they enhanceContrast or clip into a specified numerical range according to the specified ContrastEnhancementAlgorithm. %End @@ -40,12 +40,12 @@ ContrastEnhancementAlgorithm. static double maximumValuePossible( Qgis::DataType dataType ); %Docstring -Helper function that returns the maximum possible value for a GDAL data type. +Helper function that returns the maximum possible value for a data type. %End static double minimumValuePossible( Qgis::DataType dataType ); %Docstring -Helper function that returns the minimum possible value for a GDAL data type. +Helper function that returns the minimum possible value for a data type. %End static QString contrastEnhancementAlgorithmString( ContrastEnhancementAlgorithm algorithm ); diff --git a/python/core/auto_generated/raster/qgsmultibandcolorrenderer.sip.in b/python/core/auto_generated/raster/qgsmultibandcolorrenderer.sip.in index ae9c30c08bd4..229000688eee 100644 --- a/python/core/auto_generated/raster/qgsmultibandcolorrenderer.sip.in +++ b/python/core/auto_generated/raster/qgsmultibandcolorrenderer.sip.in @@ -45,21 +45,75 @@ QgsMultiBandColorRenderer cannot be copied. Use :py:func:`~QgsMultiBandColorRend void setBlueBand( int band ); const QgsContrastEnhancement *redContrastEnhancement() const; +%Docstring +Returns the contrast enchancement to use for the red channel. + +.. seealso:: :py:func:`setRedContrastEnhancement` + +.. seealso:: :py:func:`greenContrastEnhancement` + +.. seealso:: :py:func:`blueContrastEnhancement` +%End + void setRedContrastEnhancement( QgsContrastEnhancement *ce /Transfer/ ); %Docstring -Takes ownership +Sets the contrast enchancement to use for the red channel. + +Ownership of the enhancement is transferred. + +.. seealso:: :py:func:`redContrastEnhancement` + +.. seealso:: :py:func:`setGreenContrastEnhancement` + +.. seealso:: :py:func:`setBlueContrastEnhancement` %End const QgsContrastEnhancement *greenContrastEnhancement() const; +%Docstring +Returns the contrast enchancement to use for the green channel. + +.. seealso:: :py:func:`setGreenContrastEnhancement` + +.. seealso:: :py:func:`redContrastEnhancement` + +.. seealso:: :py:func:`blueContrastEnhancement` +%End + void setGreenContrastEnhancement( QgsContrastEnhancement *ce /Transfer/ ); %Docstring -Takes ownership +Sets the contrast enchancement to use for the green channel. + +Ownership of the enhancement is transferred. + +.. seealso:: :py:func:`greenContrastEnhancement` + +.. seealso:: :py:func:`setRedContrastEnhancement` + +.. seealso:: :py:func:`setBlueContrastEnhancement` %End const QgsContrastEnhancement *blueContrastEnhancement() const; +%Docstring +Returns the contrast enchancement to use for the blue channel. + +.. seealso:: :py:func:`setBlueContrastEnhancement` + +.. seealso:: :py:func:`redContrastEnhancement` + +.. seealso:: :py:func:`greenContrastEnhancement` +%End + void setBlueContrastEnhancement( QgsContrastEnhancement *ce /Transfer/ ); %Docstring -Takes ownership +Sets the contrast enchancement to use for the blue channel. + +Ownership of the enhancement is transferred. + +.. seealso:: :py:func:`blueContrastEnhancement` + +.. seealso:: :py:func:`setRedContrastEnhancement` + +.. seealso:: :py:func:`setGreenContrastEnhancement` %End virtual void writeXml( QDomDocument &doc, QDomElement &parentElem ) const; diff --git a/src/core/pointcloud/qgspointcloudrenderer.h b/src/core/pointcloud/qgspointcloudrenderer.h index 3f6a38791474..9407d2a73544 100644 --- a/src/core/pointcloud/qgspointcloudrenderer.h +++ b/src/core/pointcloud/qgspointcloudrenderer.h @@ -162,6 +162,8 @@ class CORE_EXPORT QgsPointCloudRenderer public: + QgsPointCloudRenderer() = default; + virtual ~QgsPointCloudRenderer() = default; /** @@ -175,6 +177,12 @@ class CORE_EXPORT QgsPointCloudRenderer */ virtual QgsPointCloudRenderer *clone() const = 0 SIP_FACTORY; + //! QgsPointCloudRenderer cannot be copied -- use clone() instead + QgsPointCloudRenderer( const QgsPointCloudRenderer &other ) = delete; + + //! QgsPointCloudRenderer cannot be copied -- use clone() instead + QgsPointCloudRenderer &operator=( const QgsPointCloudRenderer &other ) = delete; + /** * Renders a \a block of point cloud data using the specified render \a context. */ @@ -242,6 +250,10 @@ class CORE_EXPORT QgsPointCloudRenderer } private: +#ifdef SIP_RUN + QgsPointCloudRenderer( const QgsPointCloudRenderer &other ); +#endif + #ifdef QGISDEBUG //! Pointer to thread in which startRender was first called QThread *mThread = nullptr; diff --git a/src/core/pointcloud/qgspointcloudrgbrenderer.cpp b/src/core/pointcloud/qgspointcloudrgbrenderer.cpp index 32539f748c29..48b273b6e7c0 100644 --- a/src/core/pointcloud/qgspointcloudrgbrenderer.cpp +++ b/src/core/pointcloud/qgspointcloudrgbrenderer.cpp @@ -17,6 +17,7 @@ #include "qgspointcloudrgbrenderer.h" #include "qgspointcloudblock.h" +#include "qgscontrastenhancement.h" QgsPointCloudRgbRenderer::QgsPointCloudRgbRenderer() { @@ -35,6 +36,20 @@ QgsPointCloudRenderer *QgsPointCloudRgbRenderer::clone() const res->mRedAttribute = mRedAttribute; res->mGreenAttribute = mGreenAttribute; res->mBlueAttribute = mBlueAttribute; + + if ( mRedContrastEnhancement ) + { + res->setRedContrastEnhancement( new QgsContrastEnhancement( *mRedContrastEnhancement ) ); + } + if ( mGreenContrastEnhancement ) + { + res->setGreenContrastEnhancement( new QgsContrastEnhancement( *mGreenContrastEnhancement ) ); + } + if ( mBlueContrastEnhancement ) + { + res->setBlueContrastEnhancement( new QgsContrastEnhancement( *mBlueContrastEnhancement ) ); + } + return res.release(); } @@ -72,6 +87,10 @@ void QgsPointCloudRgbRenderer::renderBlock( const QgsPointCloudBlock *block, Qgs return; const QgsPointCloudAttribute::DataType blueType = attribute->type(); + const bool useRedContrastEnhancement = mRedContrastEnhancement && mRedContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement; + const bool useBlueContrastEnhancement = mBlueContrastEnhancement && mBlueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement; + const bool useGreenContrastEnhancement = mGreenContrastEnhancement && mGreenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement; + int rendered = 0; double x = 0; double y = 0; @@ -150,6 +169,28 @@ void QgsPointCloudRgbRenderer::renderBlock( const QgsPointCloudBlock *block, Qgs break; } + //skip if red, green or blue not in displayable range + if ( ( useRedContrastEnhancement && !mRedContrastEnhancement->isValueInDisplayableRange( red ) ) + || ( useGreenContrastEnhancement && !mGreenContrastEnhancement->isValueInDisplayableRange( green ) ) + || ( useBlueContrastEnhancement && !mBlueContrastEnhancement->isValueInDisplayableRange( blue ) ) ) + { + continue; + } + + //stretch color values + if ( useRedContrastEnhancement ) + { + red = mRedContrastEnhancement->enhanceContrast( red ); + } + if ( useGreenContrastEnhancement ) + { + green = mGreenContrastEnhancement->enhanceContrast( green ); + } + if ( useBlueContrastEnhancement ) + { + blue = mBlueContrastEnhancement->enhanceContrast( blue ); + } + mapToPixel.transformInPlace( x, y ); pen.setColor( QColor( red, green, blue ) ); @@ -172,6 +213,35 @@ QgsPointCloudRenderer *QgsPointCloudRgbRenderer::create( QDomElement &element, c r->setGreenAttribute( element.attribute( QStringLiteral( "green" ), QStringLiteral( "Green" ) ) ); r->setBlueAttribute( element.attribute( QStringLiteral( "blue" ), QStringLiteral( "Blue" ) ) ); + + //contrast enhancements + QgsContrastEnhancement *redContrastEnhancement = nullptr; + QDomElement redContrastElem = element.firstChildElement( QStringLiteral( "redContrastEnhancement" ) ); + if ( !redContrastElem.isNull() ) + { + redContrastEnhancement = new QgsContrastEnhancement( Qgis::UnknownDataType ); + redContrastEnhancement->readXml( redContrastElem ); + r->setRedContrastEnhancement( redContrastEnhancement ); + } + + QgsContrastEnhancement *greenContrastEnhancement = nullptr; + QDomElement greenContrastElem = element.firstChildElement( QStringLiteral( "greenContrastEnhancement" ) ); + if ( !greenContrastElem.isNull() ) + { + greenContrastEnhancement = new QgsContrastEnhancement( Qgis::UnknownDataType ); + greenContrastEnhancement->readXml( greenContrastElem ); + r->setGreenContrastEnhancement( greenContrastEnhancement ); + } + + QgsContrastEnhancement *blueContrastEnhancement = nullptr; + QDomElement blueContrastElem = element.firstChildElement( QStringLiteral( "blueContrastEnhancement" ) ); + if ( !blueContrastElem.isNull() ) + { + blueContrastEnhancement = new QgsContrastEnhancement( Qgis::UnknownDataType ); + blueContrastEnhancement->readXml( blueContrastElem ); + r->setBlueContrastEnhancement( blueContrastEnhancement ); + } + return r.release(); } @@ -186,6 +256,26 @@ QDomElement QgsPointCloudRgbRenderer::save( QDomDocument &doc, const QgsReadWrit rendererElem.setAttribute( QStringLiteral( "green" ), mGreenAttribute ); rendererElem.setAttribute( QStringLiteral( "blue" ), mBlueAttribute ); + //contrast enhancement + if ( mRedContrastEnhancement ) + { + QDomElement redContrastElem = doc.createElement( QStringLiteral( "redContrastEnhancement" ) ); + mRedContrastEnhancement->writeXml( doc, redContrastElem ); + rendererElem.appendChild( redContrastElem ); + } + if ( mGreenContrastEnhancement ) + { + QDomElement greenContrastElem = doc.createElement( QStringLiteral( "greenContrastEnhancement" ) ); + mGreenContrastEnhancement->writeXml( doc, greenContrastElem ); + rendererElem.appendChild( greenContrastElem ); + } + if ( mBlueContrastEnhancement ) + { + QDomElement blueContrastElem = doc.createElement( QStringLiteral( "blueContrastEnhancement" ) ); + mBlueContrastEnhancement->writeXml( doc, blueContrastElem ); + rendererElem.appendChild( blueContrastElem ); + } + return rendererElem; } @@ -245,3 +335,33 @@ void QgsPointCloudRgbRenderer::setBlueAttribute( const QString &blueAttribute ) { mBlueAttribute = blueAttribute; } + +const QgsContrastEnhancement *QgsPointCloudRgbRenderer::redContrastEnhancement() const +{ + return mRedContrastEnhancement.get(); +} + +void QgsPointCloudRgbRenderer::setRedContrastEnhancement( QgsContrastEnhancement *enhancement ) +{ + mRedContrastEnhancement.reset( enhancement ); +} + +const QgsContrastEnhancement *QgsPointCloudRgbRenderer::greenContrastEnhancement() const +{ + return mGreenContrastEnhancement.get(); +} + +void QgsPointCloudRgbRenderer::setGreenContrastEnhancement( QgsContrastEnhancement *enhancement ) +{ + mGreenContrastEnhancement.reset( enhancement ); +} + +const QgsContrastEnhancement *QgsPointCloudRgbRenderer::blueContrastEnhancement() const +{ + return mBlueContrastEnhancement.get(); +} + +void QgsPointCloudRgbRenderer::setBlueContrastEnhancement( QgsContrastEnhancement *enhancement ) +{ + mBlueContrastEnhancement.reset( enhancement ); +} diff --git a/src/core/pointcloud/qgspointcloudrgbrenderer.h b/src/core/pointcloud/qgspointcloudrgbrenderer.h index 9f04e0d60059..107da7476f37 100644 --- a/src/core/pointcloud/qgspointcloudrgbrenderer.h +++ b/src/core/pointcloud/qgspointcloudrgbrenderer.h @@ -22,6 +22,8 @@ #include "qgis_core.h" #include "qgis_sip.h" +class QgsContrastEnhancement; + /** * \ingroup core * An RGB renderer for 2d visualisation of point clouds using embedded red, green and blue attributes. @@ -36,6 +38,7 @@ class CORE_EXPORT QgsPointCloudRgbRenderer : public QgsPointCloudRenderer * Constructor for QgsPointCloudRgbRenderer. */ QgsPointCloudRgbRenderer(); + QString type() const override; QgsPointCloudRenderer *clone() const override; void renderBlock( const QgsPointCloudBlock *block, QgsPointCloudRenderContext &context ) override; @@ -109,7 +112,68 @@ class CORE_EXPORT QgsPointCloudRgbRenderer : public QgsPointCloudRenderer */ void setBlueAttribute( const QString &attribute ); + /** + * Returns the contrast enchancement to use for the red channel. + * + * \see setRedContrastEnhancement() + * \see greenContrastEnhancement() + * \see blueContrastEnhancement() + */ + const QgsContrastEnhancement *redContrastEnhancement() const; + + /** + * Sets the contrast \a enchancement to use for the red channel. + * + * Ownership of \a enhancement is transferred. + * + * \see redContrastEnhancement() + * \see setGreenContrastEnhancement() + * \see setBlueContrastEnhancement() + */ + void setRedContrastEnhancement( QgsContrastEnhancement *enhancement SIP_TRANSFER ); + + /** + * Returns the contrast enchancement to use for the green channel. + * + * \see setGreenContrastEnhancement() + * \see redContrastEnhancement() + * \see blueContrastEnhancement() + */ + const QgsContrastEnhancement *greenContrastEnhancement() const; + + /** + * Sets the contrast \a enchancement to use for the green channel. + * + * Ownership of \a enhancement is transferred. + * + * \see greenContrastEnhancement() + * \see setRedContrastEnhancement() + * \see setBlueContrastEnhancement() + */ + void setGreenContrastEnhancement( QgsContrastEnhancement *enhancement SIP_TRANSFER ); + + /** + * Returns the contrast enchancement to use for the blue channel. + * + * \see setBlueContrastEnhancement() + * \see redContrastEnhancement() + * \see greenContrastEnhancement() + */ + const QgsContrastEnhancement *blueContrastEnhancement() const; + + /** + * Sets the contrast \a enchancement to use for the blue channel. + * + * Ownership of \a enhancement is transferred. + * + * \see blueContrastEnhancement() + * \see setRedContrastEnhancement() + * \see setGreenContrastEnhancement() + */ + void setBlueContrastEnhancement( QgsContrastEnhancement *enhancement SIP_TRANSFER ); + private: + int mPenWidth = 1; int mPainterPenWidth = 1; @@ -117,6 +181,10 @@ class CORE_EXPORT QgsPointCloudRgbRenderer : public QgsPointCloudRenderer QString mGreenAttribute = QStringLiteral( "Green" ); QString mBlueAttribute = QStringLiteral( "Blue" ); + std::unique_ptr< QgsContrastEnhancement > mRedContrastEnhancement; + std::unique_ptr< QgsContrastEnhancement > mGreenContrastEnhancement; + std::unique_ptr< QgsContrastEnhancement > mBlueContrastEnhancement; + }; #endif // QGSPOINTCLOUDRGBRENDERER_H diff --git a/src/core/raster/qgscontrastenhancement.h b/src/core/raster/qgscontrastenhancement.h index 463b4a019c71..3fd040a8c32e 100644 --- a/src/core/raster/qgscontrastenhancement.h +++ b/src/core/raster/qgscontrastenhancement.h @@ -35,7 +35,7 @@ class QString; /** * \ingroup core - * Manipulates raster pixel values so that they enhanceContrast or clip into a + * Manipulates raster or point cloud pixel values so that they enhanceContrast or clip into a * specified numerical range according to the specified * ContrastEnhancementAlgorithm. */ @@ -47,8 +47,8 @@ class CORE_EXPORT QgsContrastEnhancement //! \brief This enumerator describes the types of contrast enhancement algorithms that can be used. enum ContrastEnhancementAlgorithm { - NoEnhancement, //this should be the default color scaling algorithm - StretchToMinimumMaximum, //linear histogram enhanceContrast + NoEnhancement, //!< Default color scaling algorithm, no scaling is applied + StretchToMinimumMaximum, //!< Linear histogram StretchAndClipToMinimumMaximum, ClipToMinimumMaximum, UserDefinedEnhancement @@ -61,7 +61,7 @@ class CORE_EXPORT QgsContrastEnhancement const QgsContrastEnhancement &operator=( const QgsContrastEnhancement & ) = delete; /** - * Helper function that returns the maximum possible value for a GDAL data type. + * Helper function that returns the maximum possible value for a data type. */ static double maximumValuePossible( Qgis::DataType dataType ) { @@ -100,7 +100,7 @@ class CORE_EXPORT QgsContrastEnhancement } /** - * Helper function that returns the minimum possible value for a GDAL data type. + * Helper function that returns the minimum possible value for a data type. */ static double minimumValuePossible( Qgis::DataType dataType ) { diff --git a/src/core/raster/qgsmultibandcolorrenderer.h b/src/core/raster/qgsmultibandcolorrenderer.h index 132aa2a591fd..5bcf184cfb15 100644 --- a/src/core/raster/qgsmultibandcolorrenderer.h +++ b/src/core/raster/qgsmultibandcolorrenderer.h @@ -55,16 +55,64 @@ class CORE_EXPORT QgsMultiBandColorRenderer: public QgsRasterRenderer int blueBand() const { return mBlueBand; } void setBlueBand( int band ) { mBlueBand = band; } + /** + * Returns the contrast enchancement to use for the red channel. + * + * \see setRedContrastEnhancement() + * \see greenContrastEnhancement() + * \see blueContrastEnhancement() + */ const QgsContrastEnhancement *redContrastEnhancement() const { return mRedContrastEnhancement; } - //! Takes ownership + + /** + * Sets the contrast enchancement to use for the red channel. + * + * Ownership of the enhancement is transferred. + * + * \see redContrastEnhancement() + * \see setGreenContrastEnhancement() + * \see setBlueContrastEnhancement() + */ void setRedContrastEnhancement( QgsContrastEnhancement *ce SIP_TRANSFER ); + /** + * Returns the contrast enchancement to use for the green channel. + * + * \see setGreenContrastEnhancement() + * \see redContrastEnhancement() + * \see blueContrastEnhancement() + */ const QgsContrastEnhancement *greenContrastEnhancement() const { return mGreenContrastEnhancement; } - //! Takes ownership + + /** + * Sets the contrast enchancement to use for the green channel. + * + * Ownership of the enhancement is transferred. + * + * \see greenContrastEnhancement() + * \see setRedContrastEnhancement() + * \see setBlueContrastEnhancement() + */ void setGreenContrastEnhancement( QgsContrastEnhancement *ce SIP_TRANSFER ); + /** + * Returns the contrast enchancement to use for the blue channel. + * + * \see setBlueContrastEnhancement() + * \see redContrastEnhancement() + * \see greenContrastEnhancement() + */ const QgsContrastEnhancement *blueContrastEnhancement() const { return mBlueContrastEnhancement; } - //! Takes ownership + + /** + * Sets the contrast enchancement to use for the blue channel. + * + * Ownership of the enhancement is transferred. + * + * \see blueContrastEnhancement() + * \see setRedContrastEnhancement() + * \see setGreenContrastEnhancement() + */ void setBlueContrastEnhancement( QgsContrastEnhancement *ce SIP_TRANSFER ); void writeXml( QDomDocument &doc, QDomElement &parentElem ) const override; diff --git a/tests/src/python/test_qgspointcloudrgbrenderer.py b/tests/src/python/test_qgspointcloudrgbrenderer.py index 7e6c9516963f..270e30bc871f 100644 --- a/tests/src/python/test_qgspointcloudrgbrenderer.py +++ b/tests/src/python/test_qgspointcloudrgbrenderer.py @@ -22,7 +22,8 @@ QgsVector3D, QgsMultiRenderChecker, QgsMapSettings, - QgsRectangle + QgsRectangle, + QgsContrastEnhancement ) from qgis.PyQt.QtCore import QDir, QSize @@ -64,10 +65,37 @@ def testBasic(self): renderer.setRedAttribute('r') self.assertEqual(renderer.redAttribute(), 'r') + redce = QgsContrastEnhancement() + redce.setMinimumValue(100) + redce.setMaximumValue(120) + redce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchAndClipToMinimumMaximum) + renderer.setRedContrastEnhancement(redce) + + greence = QgsContrastEnhancement() + greence.setMinimumValue(130) + greence.setMaximumValue(150) + greence.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum) + renderer.setGreenContrastEnhancement(greence) + + bluece = QgsContrastEnhancement() + bluece.setMinimumValue(170) + bluece.setMaximumValue(190) + bluece.setContrastEnhancementAlgorithm(QgsContrastEnhancement.ClipToMinimumMaximum) + renderer.setBlueContrastEnhancement(bluece) + rr = renderer.clone() self.assertEqual(rr.blueAttribute(), 'b') self.assertEqual(rr.greenAttribute(), 'g') self.assertEqual(rr.redAttribute(), 'r') + self.assertEqual(rr.redContrastEnhancement().minimumValue(), 100) + self.assertEqual(rr.redContrastEnhancement().maximumValue(), 120) + self.assertEqual(rr.redContrastEnhancement().contrastEnhancementAlgorithm(), QgsContrastEnhancement.StretchAndClipToMinimumMaximum) + self.assertEqual(rr.greenContrastEnhancement().minimumValue(), 130) + self.assertEqual(rr.greenContrastEnhancement().maximumValue(), 150) + self.assertEqual(rr.greenContrastEnhancement().contrastEnhancementAlgorithm(), QgsContrastEnhancement.StretchToMinimumMaximum) + self.assertEqual(rr.blueContrastEnhancement().minimumValue(), 170) + self.assertEqual(rr.blueContrastEnhancement().maximumValue(), 190) + self.assertEqual(rr.blueContrastEnhancement().contrastEnhancementAlgorithm(), QgsContrastEnhancement.ClipToMinimumMaximum) doc = QDomDocument("testdoc") elem = renderer.save(doc, QgsReadWriteContext()) @@ -76,6 +104,15 @@ def testBasic(self): self.assertEqual(r2.blueAttribute(), 'b') self.assertEqual(r2.greenAttribute(), 'g') self.assertEqual(r2.redAttribute(), 'r') + self.assertEqual(r2.redContrastEnhancement().minimumValue(), 100) + self.assertEqual(r2.redContrastEnhancement().maximumValue(), 120) + self.assertEqual(r2.redContrastEnhancement().contrastEnhancementAlgorithm(), QgsContrastEnhancement.StretchAndClipToMinimumMaximum) + self.assertEqual(r2.greenContrastEnhancement().minimumValue(), 130) + self.assertEqual(r2.greenContrastEnhancement().maximumValue(), 150) + self.assertEqual(r2.greenContrastEnhancement().contrastEnhancementAlgorithm(), QgsContrastEnhancement.StretchToMinimumMaximum) + self.assertEqual(r2.blueContrastEnhancement().minimumValue(), 170) + self.assertEqual(r2.blueContrastEnhancement().maximumValue(), 190) + self.assertEqual(r2.blueContrastEnhancement().contrastEnhancementAlgorithm(), QgsContrastEnhancement.ClipToMinimumMaximum) def testUsedAttributes(self): renderer = QgsPointCloudRgbRenderer() @@ -110,6 +147,46 @@ def testRender(self): TestQgsPointCloudRgbRenderer.report += renderchecker.report() self.assertTrue(result) + @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') + def testRenderWithContrast(self): + layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') + self.assertTrue(layer.isValid()) + + layer.renderer().setPenWidth(2) + + redce = QgsContrastEnhancement() + redce.setMinimumValue(100) + redce.setMaximumValue(120) + redce.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum) + layer.renderer().setRedContrastEnhancement(redce) + + greence = QgsContrastEnhancement() + greence.setMinimumValue(130) + greence.setMaximumValue(150) + greence.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum) + layer.renderer().setGreenContrastEnhancement(greence) + + bluece = QgsContrastEnhancement() + bluece.setMinimumValue(170) + bluece.setMaximumValue(190) + bluece.setContrastEnhancementAlgorithm(QgsContrastEnhancement.StretchToMinimumMaximum) + layer.renderer().setBlueContrastEnhancement(bluece) + + mapsettings = QgsMapSettings() + mapsettings.setOutputSize(QSize(400, 400)) + mapsettings.setOutputDpi(96) + mapsettings.setDestinationCrs(layer.crs()) + mapsettings.setExtent(QgsRectangle(497753.5, 7050887.5, 497754.6, 7050888.6)) + mapsettings.setLayers([layer]) + + renderchecker = QgsMultiRenderChecker() + renderchecker.setMapSettings(mapsettings) + renderchecker.setControlPathPrefix('pointcloudrenderer') + renderchecker.setControlName('expected_rgb_contrast') + result = renderchecker.runTest('expected_rgb_contrast') + TestQgsPointCloudRgbRenderer.report += renderchecker.report() + self.assertTrue(result) + @unittest.skipIf('ept' not in QgsProviderRegistry.instance().providerList(), 'EPT provider not available') def testRenderOpacity(self): layer = QgsPointCloudLayer(unitTestDataPath() + '/point_clouds/ept/rgb/ept.json', 'test', 'ept') diff --git a/tests/testdata/control_images/pointcloudrenderer/expected_rgb_contrast/expected_rgb_contrast.png b/tests/testdata/control_images/pointcloudrenderer/expected_rgb_contrast/expected_rgb_contrast.png new file mode 100644 index 000000000000..0d5518d85a6e Binary files /dev/null and b/tests/testdata/control_images/pointcloudrenderer/expected_rgb_contrast/expected_rgb_contrast.png differ