Support contrast enhancement and manual selection of RGB attributes

in 3d RBB point cloud renderer
This commit is contained in:
Nyall Dawson 2020-12-04 16:29:36 +10:00 committed by Mathieu Pellerin
parent c2600e03a3
commit da162726e4
7 changed files with 1013 additions and 30 deletions

View File

@ -233,8 +233,13 @@ class QgsRgbPointCloud3DSymbol : QgsPointCloud3DSymbol
Constructor for :py:class:`QgsRGBPointCloud3DSymbol`
%End
virtual QString symbolType() const;
%Docstring
QgsRgbPointCloud3DSymbol cannot be copied - use :py:func:`~QgsRgbPointCloud3DSymbol.clone` instead
%End
virtual QgsAbstract3DSymbol *clone() const /Factory/;
@ -244,6 +249,147 @@ Constructor for :py:class:`QgsRGBPointCloud3DSymbol`
virtual unsigned int byteStride();
QString redAttribute() const;
%Docstring
Returns the attribute to use for the red channel.
.. seealso:: :py:func:`greenAttribute`
.. seealso:: :py:func:`blueAttribute`
.. seealso:: :py:func:`setRedAttribute`
%End
void setRedAttribute( const QString &attribute );
%Docstring
Sets the ``attribute`` to use for the red channel.
.. seealso:: :py:func:`setGreenAttribute`
.. seealso:: :py:func:`setBlueAttribute`
.. seealso:: :py:func:`redAttribute`
%End
QString greenAttribute() const;
%Docstring
Returns the attribute to use for the green channel.
.. seealso:: :py:func:`redAttribute`
.. seealso:: :py:func:`blueAttribute`
.. seealso:: :py:func:`setGreenAttribute`
%End
void setGreenAttribute( const QString &attribute );
%Docstring
Sets the ``attribute`` to use for the green channel.
.. seealso:: :py:func:`setRedAttribute`
.. seealso:: :py:func:`setBlueAttribute`
.. seealso:: :py:func:`greenAttribute`
%End
QString blueAttribute() const;
%Docstring
Returns the attribute to use for the blue channel.
.. seealso:: :py:func:`greenAttribute`
.. seealso:: :py:func:`redAttribute`
.. seealso:: :py:func:`setBlueAttribute`
%End
void setBlueAttribute( const QString &attribute );
%Docstring
Sets the ``attribute`` to use for the blue channel.
.. seealso:: :py:func:`setRedAttribute`
.. seealso:: :py:func:`setGreenAttribute`
.. seealso:: :py:func:`blueAttribute`
%End
QgsContrastEnhancement *redContrastEnhancement();
%Docstring
Returns the contrast enhancement 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 ``enhancement`` to use for the red channel.
Ownership of ``enhancement`` is transferred.
.. seealso:: :py:func:`redContrastEnhancement`
.. seealso:: :py:func:`setGreenContrastEnhancement`
.. seealso:: :py:func:`setBlueContrastEnhancement`
%End
QgsContrastEnhancement *greenContrastEnhancement();
%Docstring
Returns the contrast enhancement 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 ``enhancement`` to use for the green channel.
Ownership of ``enhancement`` is transferred.
.. seealso:: :py:func:`greenContrastEnhancement`
.. seealso:: :py:func:`setRedContrastEnhancement`
.. seealso:: :py:func:`setBlueContrastEnhancement`
%End
QgsContrastEnhancement *blueContrastEnhancement();
%Docstring
Returns the contrast enhancement 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 ``enhancement`` to use for the blue channel.
Ownership of ``enhancement`` is transferred.
.. seealso:: :py:func:`blueContrastEnhancement`
.. seealso:: :py:func:`setRedContrastEnhancement`
.. seealso:: :py:func:`setGreenContrastEnhancement`
%End
private:
QgsRgbPointCloud3DSymbol( const QgsRgbPointCloud3DSymbol &other );
};
/************************************************************************

View File

@ -208,6 +208,22 @@ QgsAbstract3DSymbol *QgsRgbPointCloud3DSymbol::clone() const
{
QgsRgbPointCloud3DSymbol *result = new QgsRgbPointCloud3DSymbol;
result->mPointSize = mPointSize;
result->mRedAttribute = mRedAttribute;
result->mGreenAttribute = mGreenAttribute;
result->mBlueAttribute = mBlueAttribute;
if ( mRedContrastEnhancement )
{
result->setRedContrastEnhancement( new QgsContrastEnhancement( *mRedContrastEnhancement ) );
}
if ( mGreenContrastEnhancement )
{
result->setGreenContrastEnhancement( new QgsContrastEnhancement( *mGreenContrastEnhancement ) );
}
if ( mBlueContrastEnhancement )
{
result->setBlueContrastEnhancement( new QgsContrastEnhancement( *mBlueContrastEnhancement ) );
}
copyBaseSettings( result );
return result;
}
@ -216,12 +232,70 @@ void QgsRgbPointCloud3DSymbol::writeXml( QDomElement &elem, const QgsReadWriteCo
{
Q_UNUSED( context )
elem.setAttribute( QStringLiteral( "point-size" ), mPointSize );
elem.setAttribute( QStringLiteral( "red" ), mRedAttribute );
elem.setAttribute( QStringLiteral( "green" ), mGreenAttribute );
elem.setAttribute( QStringLiteral( "blue" ), mBlueAttribute );
QDomDocument doc = elem.ownerDocument();
//contrast enhancement
if ( mRedContrastEnhancement )
{
QDomElement redContrastElem = doc.createElement( QStringLiteral( "redContrastEnhancement" ) );
mRedContrastEnhancement->writeXml( doc, redContrastElem );
elem.appendChild( redContrastElem );
}
if ( mGreenContrastEnhancement )
{
QDomElement greenContrastElem = doc.createElement( QStringLiteral( "greenContrastEnhancement" ) );
mGreenContrastEnhancement->writeXml( doc, greenContrastElem );
elem.appendChild( greenContrastElem );
}
if ( mBlueContrastEnhancement )
{
QDomElement blueContrastElem = doc.createElement( QStringLiteral( "blueContrastEnhancement" ) );
mBlueContrastEnhancement->writeXml( doc, blueContrastElem );
elem.appendChild( blueContrastElem );
}
}
void QgsRgbPointCloud3DSymbol::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
Q_UNUSED( context )
mPointSize = elem.attribute( "point-size", QStringLiteral( "2.0" ) ).toFloat();
setRedAttribute( elem.attribute( QStringLiteral( "red" ), QStringLiteral( "Red" ) ) );
setGreenAttribute( elem.attribute( QStringLiteral( "green" ), QStringLiteral( "Green" ) ) );
setBlueAttribute( elem.attribute( QStringLiteral( "blue" ), QStringLiteral( "Blue" ) ) );
//contrast enhancements
QgsContrastEnhancement *redContrastEnhancement = nullptr;
QDomElement redContrastElem = elem.firstChildElement( QStringLiteral( "redContrastEnhancement" ) );
if ( !redContrastElem.isNull() )
{
redContrastEnhancement = new QgsContrastEnhancement( Qgis::UnknownDataType );
redContrastEnhancement->readXml( redContrastElem );
setRedContrastEnhancement( redContrastEnhancement );
}
QgsContrastEnhancement *greenContrastEnhancement = nullptr;
QDomElement greenContrastElem = elem.firstChildElement( QStringLiteral( "greenContrastEnhancement" ) );
if ( !greenContrastElem.isNull() )
{
greenContrastEnhancement = new QgsContrastEnhancement( Qgis::UnknownDataType );
greenContrastEnhancement->readXml( greenContrastElem );
setGreenContrastEnhancement( greenContrastEnhancement );
}
QgsContrastEnhancement *blueContrastEnhancement = nullptr;
QDomElement blueContrastElem = elem.firstChildElement( QStringLiteral( "blueContrastEnhancement" ) );
if ( !blueContrastElem.isNull() )
{
blueContrastEnhancement = new QgsContrastEnhancement( Qgis::UnknownDataType );
blueContrastEnhancement->readXml( blueContrastElem );
setBlueContrastEnhancement( blueContrastEnhancement );
}
}
void QgsRgbPointCloud3DSymbol::fillMaterial( Qt3DRender::QMaterial *mat )
@ -231,3 +305,65 @@ void QgsRgbPointCloud3DSymbol::fillMaterial( Qt3DRender::QMaterial *mat )
Qt3DRender::QParameter *pointSizeParameter = new Qt3DRender::QParameter( "u_pointSize", QVariant::fromValue( mPointSize ) );
mat->addParameter( pointSizeParameter );
}
QString QgsRgbPointCloud3DSymbol::redAttribute() const
{
return mRedAttribute;
}
void QgsRgbPointCloud3DSymbol::setRedAttribute( const QString &redAttribute )
{
mRedAttribute = redAttribute;
}
QString QgsRgbPointCloud3DSymbol::greenAttribute() const
{
return mGreenAttribute;
}
void QgsRgbPointCloud3DSymbol::setGreenAttribute( const QString &greenAttribute )
{
mGreenAttribute = greenAttribute;
}
QString QgsRgbPointCloud3DSymbol::blueAttribute() const
{
return mBlueAttribute;
}
void QgsRgbPointCloud3DSymbol::setBlueAttribute( const QString &blueAttribute )
{
mBlueAttribute = blueAttribute;
}
QgsContrastEnhancement *QgsRgbPointCloud3DSymbol::redContrastEnhancement()
{
return mRedContrastEnhancement.get();
}
void QgsRgbPointCloud3DSymbol::setRedContrastEnhancement( QgsContrastEnhancement *enhancement )
{
mRedContrastEnhancement.reset( enhancement );
}
QgsContrastEnhancement *QgsRgbPointCloud3DSymbol::greenContrastEnhancement()
{
return mGreenContrastEnhancement.get();
}
void QgsRgbPointCloud3DSymbol::setGreenContrastEnhancement( QgsContrastEnhancement *enhancement )
{
mGreenContrastEnhancement.reset( enhancement );
}
QgsContrastEnhancement *QgsRgbPointCloud3DSymbol::blueContrastEnhancement()
{
return mBlueContrastEnhancement.get();
}
void QgsRgbPointCloud3DSymbol::setBlueContrastEnhancement( QgsContrastEnhancement *enhancement )
{
mBlueContrastEnhancement.reset( enhancement );
}

View File

@ -23,6 +23,7 @@
#include "qgsabstract3dsymbol.h"
#include "qgscolorrampshader.h"
#include "qgspointcloudlayer.h"
#include "qgscontrastenhancement.h"
/**
* \ingroup 3d
@ -214,6 +215,12 @@ class _3D_EXPORT QgsRgbPointCloud3DSymbol : public QgsPointCloud3DSymbol
//! Constructor for QgsRGBPointCloud3DSymbol
QgsRgbPointCloud3DSymbol();
//! QgsRgbPointCloud3DSymbol cannot be copied - use clone() instead
QgsRgbPointCloud3DSymbol( const QgsRgbPointCloud3DSymbol &other ) = delete;
//! QgsRgbPointCloud3DSymbol cannot be copied - use clone() instead
QgsRgbPointCloud3DSymbol &operator=( const QgsRgbPointCloud3DSymbol &other ) = delete;
QString symbolType() const override;
QgsAbstract3DSymbol *clone() const override SIP_FACTORY;
@ -222,6 +229,135 @@ class _3D_EXPORT QgsRgbPointCloud3DSymbol : public QgsPointCloud3DSymbol
unsigned int byteStride() override { return 6 * sizeof( float ); }
void fillMaterial( Qt3DRender::QMaterial *material ) override SIP_SKIP;
/**
* Returns the attribute to use for the red channel.
*
* \see greenAttribute()
* \see blueAttribute()
* \see setRedAttribute()
*/
QString redAttribute() const;
/**
* Sets the \a attribute to use for the red channel.
*
* \see setGreenAttribute()
* \see setBlueAttribute()
* \see redAttribute()
*/
void setRedAttribute( const QString &attribute );
/**
* Returns the attribute to use for the green channel.
*
* \see redAttribute()
* \see blueAttribute()
* \see setGreenAttribute()
*/
QString greenAttribute() const;
/**
* Sets the \a attribute to use for the green channel.
*
* \see setRedAttribute()
* \see setBlueAttribute()
* \see greenAttribute()
*/
void setGreenAttribute( const QString &attribute );
/**
* Returns the attribute to use for the blue channel.
*
* \see greenAttribute()
* \see redAttribute()
* \see setBlueAttribute()
*/
QString blueAttribute() const;
/**
* Sets the \a attribute to use for the blue channel.
*
* \see setRedAttribute()
* \see setGreenAttribute()
* \see blueAttribute()
*/
void setBlueAttribute( const QString &attribute );
/**
* Returns the contrast enhancement to use for the red channel.
*
* \see setRedContrastEnhancement()
* \see greenContrastEnhancement()
* \see blueContrastEnhancement()
*/
QgsContrastEnhancement *redContrastEnhancement();
/**
* Sets the contrast \a enhancement 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 enhancement to use for the green channel.
*
* \see setGreenContrastEnhancement()
* \see redContrastEnhancement()
* \see blueContrastEnhancement()
*/
QgsContrastEnhancement *greenContrastEnhancement();
/**
* Sets the contrast \a enhancement 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 enhancement to use for the blue channel.
*
* \see setBlueContrastEnhancement()
* \see redContrastEnhancement()
* \see greenContrastEnhancement()
*/
QgsContrastEnhancement *blueContrastEnhancement();
/**
* Sets the contrast \a enhancement 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:
#ifdef SIP_RUN
QgsRgbPointCloud3DSymbol( const QgsRgbPointCloud3DSymbol &other );
#endif
QString mRedAttribute = QStringLiteral( "Red" );
QString mGreenAttribute = QStringLiteral( "Green" );
QString mBlueAttribute = QStringLiteral( "Blue" );
std::unique_ptr< QgsContrastEnhancement > mRedContrastEnhancement;
std::unique_ptr< QgsContrastEnhancement > mGreenContrastEnhancement;
std::unique_ptr< QgsContrastEnhancement > mBlueContrastEnhancement;
};
#endif // QGSPOINTCLOUD3DSYMBOL_H

View File

@ -419,21 +419,23 @@ void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const
attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Y" ), QgsPointCloudAttribute::Int32 ) );
attributes.push_back( QgsPointCloudAttribute( QStringLiteral( "Z" ), QgsPointCloudAttribute::Int32 ) );
QgsRgbPointCloud3DSymbol *symbol = dynamic_cast<QgsRgbPointCloud3DSymbol *>( context.symbol() );
// we have to get the RGB attributes using their real data types -- they aren't always short! (sometimes unsigned short)
int attrOffset = 0 ;
const int redOffset = attributes.pointRecordSize();
const QgsPointCloudAttribute *colorAttribute = context.attributes().find( QStringLiteral( "Red" ), attrOffset );
const QgsPointCloudAttribute *colorAttribute = context.attributes().find( symbol->redAttribute(), attrOffset );
attributes.push_back( *colorAttribute );
const QgsPointCloudAttribute::DataType redType = colorAttribute->type();
const int greenOffset = attributes.pointRecordSize();
colorAttribute = context.attributes().find( QStringLiteral( "Green" ), attrOffset );
colorAttribute = context.attributes().find( symbol->greenAttribute(), attrOffset );
attributes.push_back( *colorAttribute );
const QgsPointCloudAttribute::DataType greenType = colorAttribute->type();
const int blueOffset = attributes.pointRecordSize();
colorAttribute = context.attributes().find( QStringLiteral( "Blue" ), attrOffset );
colorAttribute = context.attributes().find( symbol->blueAttribute(), attrOffset );
attributes.push_back( *colorAttribute );
const QgsPointCloudAttribute::DataType blueType = colorAttribute->type();
@ -450,9 +452,17 @@ void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const
const QgsVector3D scale = pc->scale();
const QgsVector3D offset = pc->offset();
float ir = 0;
float ig = 0;
float ib = 0;
QgsContrastEnhancement *redContrastEnhancement = symbol->redContrastEnhancement();
QgsContrastEnhancement *greenContrastEnhancement = symbol->greenContrastEnhancement();
QgsContrastEnhancement *blueContrastEnhancement = symbol->blueContrastEnhancement();
const bool useRedContrastEnhancement = redContrastEnhancement && redContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
const bool useBlueContrastEnhancement = blueContrastEnhancement && blueContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
const bool useGreenContrastEnhancement = greenContrastEnhancement && greenContrastEnhancement->contrastEnhancementAlgorithm() != QgsContrastEnhancement::NoEnhancement;
int ir = 0;
int ig = 0;
int ib = 0;
for ( int i = 0; i < count; ++i )
{
qint32 ix = *( qint32 * )( ptr + i * recordSize + 0 );
@ -463,17 +473,40 @@ void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const
double z = offset.z() + scale.z() * iz;
QVector3D point( x, y, z );
QgsVector3D p = context.map().mapToWorldCoordinates( point );
outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
QVector3D color( 0.0f, 0.0f, 0.0f );
context.getAttribute( ptr, i * recordSize + redOffset, redType, ir );
color.setX( ir / 255.0f );
context.getAttribute( ptr, i * recordSize + greenOffset, greenType, ig );
color.setY( ig / 255.0f );
context.getAttribute( ptr, i * recordSize + blueOffset, blueType, ib );
//skip if red, green or blue not in displayable range
if ( ( useRedContrastEnhancement && !redContrastEnhancement->isValueInDisplayableRange( ir ) )
|| ( useGreenContrastEnhancement && !greenContrastEnhancement->isValueInDisplayableRange( ig ) )
|| ( useBlueContrastEnhancement && !blueContrastEnhancement->isValueInDisplayableRange( ib ) ) )
{
continue;
}
//stretch color values
if ( useRedContrastEnhancement )
{
ir = redContrastEnhancement->enhanceContrast( ir );
}
if ( useGreenContrastEnhancement )
{
ig = greenContrastEnhancement->enhanceContrast( ig );
}
if ( useBlueContrastEnhancement )
{
ib = blueContrastEnhancement->enhanceContrast( ib );
}
color.setX( ir / 255.0f );
color.setY( ig / 255.0f );
color.setZ( ib / 255.0f );
outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
outNormal.colors.push_back( color );
}
}

View File

@ -22,6 +22,7 @@
#include "qgspointcloudrenderer.h"
#include "qgspointcloudattributebyramprenderer.h"
#include "qgspointcloudrgbrenderer.h"
#include "qgsdoublevalidator.h"
QgsPointCloud3DSymbolWidget::QgsPointCloud3DSymbolWidget( QgsPointCloudLayer *layer, QgsPointCloud3DSymbol *symbol, QWidget *parent )
: QWidget( parent )
@ -44,6 +45,41 @@ QgsPointCloud3DSymbolWidget::QgsPointCloud3DSymbolWidget( QgsPointCloudLayer *la
mRenderingStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "styleicons/singlebandpseudocolor.svg" ) ), tr( "Attribute by Ramp" ), QStringLiteral( "color-ramp" ) );
mRenderingStyleComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "styleicons/multibandcolor.svg" ) ), tr( "RGB" ), QStringLiteral( "rgb" ) );
connect( mRedMinLineEdit, &QLineEdit::textChanged, this, &QgsPointCloud3DSymbolWidget::mRedMinLineEdit_textChanged );
connect( mRedMaxLineEdit, &QLineEdit::textChanged, this, &QgsPointCloud3DSymbolWidget::mRedMaxLineEdit_textChanged );
connect( mGreenMinLineEdit, &QLineEdit::textChanged, this, &QgsPointCloud3DSymbolWidget::mGreenMinLineEdit_textChanged );
connect( mGreenMaxLineEdit, &QLineEdit::textChanged, this, &QgsPointCloud3DSymbolWidget::mGreenMaxLineEdit_textChanged );
connect( mBlueMinLineEdit, &QLineEdit::textChanged, this, &QgsPointCloud3DSymbolWidget::mBlueMinLineEdit_textChanged );
connect( mBlueMaxLineEdit, &QLineEdit::textChanged, this, &QgsPointCloud3DSymbolWidget::mBlueMaxLineEdit_textChanged );
createValidators();
mRedAttributeComboBox->setAllowEmptyAttributeName( true );
mGreenAttributeComboBox->setAllowEmptyAttributeName( true );
mBlueAttributeComboBox->setAllowEmptyAttributeName( true );
//contrast enhancement algorithms
mContrastEnhancementAlgorithmComboBox->addItem( tr( "No Enhancement" ), QgsContrastEnhancement::NoEnhancement );
mContrastEnhancementAlgorithmComboBox->addItem( tr( "Stretch to MinMax" ), QgsContrastEnhancement::StretchToMinimumMaximum );
mContrastEnhancementAlgorithmComboBox->addItem( tr( "Stretch and Clip to MinMax" ), QgsContrastEnhancement::StretchAndClipToMinimumMaximum );
mContrastEnhancementAlgorithmComboBox->addItem( tr( "Clip to MinMax" ), QgsContrastEnhancement::ClipToMinimumMaximum );
mRedAttributeComboBox->setLayer( layer );
mGreenAttributeComboBox->setLayer( layer );
mBlueAttributeComboBox->setLayer( layer );
connect( mRedAttributeComboBox, &QgsPointCloudAttributeComboBox::attributeChanged,
this, &QgsPointCloud3DSymbolWidget::redAttributeChanged );
connect( mGreenAttributeComboBox, &QgsPointCloudAttributeComboBox::attributeChanged,
this, &QgsPointCloud3DSymbolWidget::greenAttributeChanged );
connect( mBlueAttributeComboBox, &QgsPointCloudAttributeComboBox::attributeChanged,
this, &QgsPointCloud3DSymbolWidget::blueAttributeChanged );
connect( mContrastEnhancementAlgorithmComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointCloud3DSymbolWidget::emitChangedSignal );
// set nice initial values
redAttributeChanged();
greenAttributeChanged();
blueAttributeChanged();
mRenderingStyleComboBox->setCurrentIndex( 0 );
mStackedWidget->setCurrentIndex( 0 );
@ -99,6 +135,17 @@ void QgsPointCloud3DSymbolWidget::setSymbol( QgsPointCloud3DSymbol *symbol )
else if ( symbol->symbolType() == QLatin1String( "rgb" ) )
{
mStackedWidget->setCurrentIndex( 3 );
QgsRgbPointCloud3DSymbol *symb = dynamic_cast<QgsRgbPointCloud3DSymbol *>( symbol );
mRedAttributeComboBox->setAttribute( symb->redAttribute() );
mGreenAttributeComboBox->setAttribute( symb->greenAttribute() );
mBlueAttributeComboBox->setAttribute( symb->blueAttribute() );
mDisableMinMaxWidgetRefresh++;
setMinMaxValue( symb->redContrastEnhancement(), mRedMinLineEdit, mRedMaxLineEdit );
setMinMaxValue( symb->greenContrastEnhancement(), mGreenMinLineEdit, mGreenMaxLineEdit );
setMinMaxValue( symb->blueContrastEnhancement(), mBlueMinLineEdit, mBlueMaxLineEdit );
mDisableMinMaxWidgetRefresh--;
}
else
{
@ -133,6 +180,12 @@ QgsPointCloud3DSymbol *QgsPointCloud3DSymbolWidget::symbol() const
{
QgsRgbPointCloud3DSymbol *symb = new QgsRgbPointCloud3DSymbol;
symb->setPointSize( mPointSizeSpinBox->value() );
symb->setRedAttribute( mRedAttributeComboBox->currentAttribute() );
symb->setGreenAttribute( mGreenAttributeComboBox->currentAttribute() );
symb->setBlueAttribute( mBlueAttributeComboBox->currentAttribute() );
setCustomMinMaxValues( symb );
retSymb = symb;
}
@ -145,6 +198,122 @@ void QgsPointCloud3DSymbolWidget::setColorRampMinMax( double min, double max )
whileBlocking( mColorRampShaderMaxEdit )->setValue( max );
}
void QgsPointCloud3DSymbolWidget::createValidators()
{
mRedMinLineEdit->setValidator( new QgsDoubleValidator( mRedMinLineEdit ) );
mRedMaxLineEdit->setValidator( new QgsDoubleValidator( mRedMinLineEdit ) );
mGreenMinLineEdit->setValidator( new QgsDoubleValidator( mGreenMinLineEdit ) );
mGreenMaxLineEdit->setValidator( new QgsDoubleValidator( mGreenMinLineEdit ) );
mBlueMinLineEdit->setValidator( new QgsDoubleValidator( mBlueMinLineEdit ) );
mBlueMaxLineEdit->setValidator( new QgsDoubleValidator( mBlueMinLineEdit ) );
}
void QgsPointCloud3DSymbolWidget::setCustomMinMaxValues( QgsRgbPointCloud3DSymbol *symbol ) const
{
if ( !symbol )
{
return;
}
if ( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ==
QgsContrastEnhancement::NoEnhancement )
{
symbol->setRedContrastEnhancement( nullptr );
symbol->setGreenContrastEnhancement( nullptr );
symbol->setBlueContrastEnhancement( nullptr );
return;
}
QgsContrastEnhancement *redEnhancement = nullptr;
QgsContrastEnhancement *greenEnhancement = nullptr;
QgsContrastEnhancement *blueEnhancement = nullptr;
bool redMinOk, redMaxOk;
double redMin = QgsDoubleValidator::toDouble( mRedMinLineEdit->text(), &redMinOk );
double redMax = QgsDoubleValidator::toDouble( mRedMaxLineEdit->text(), &redMaxOk );
if ( redMinOk && redMaxOk && !mRedAttributeComboBox->currentAttribute().isEmpty() )
{
redEnhancement = new QgsContrastEnhancement( Qgis::UnknownDataType );
redEnhancement->setMinimumValue( redMin );
redEnhancement->setMaximumValue( redMax );
}
bool greenMinOk, greenMaxOk;
double greenMin = QgsDoubleValidator::toDouble( mGreenMinLineEdit->text(), &greenMinOk );
double greenMax = QgsDoubleValidator::toDouble( mGreenMaxLineEdit->text(), &greenMaxOk );
if ( greenMinOk && greenMaxOk && !mGreenAttributeComboBox->currentAttribute().isEmpty() )
{
greenEnhancement = new QgsContrastEnhancement( Qgis::UnknownDataType );
greenEnhancement->setMinimumValue( greenMin );
greenEnhancement->setMaximumValue( greenMax );
}
bool blueMinOk, blueMaxOk;
double blueMin = QgsDoubleValidator::toDouble( mBlueMinLineEdit->text(), &blueMinOk );
double blueMax = QgsDoubleValidator::toDouble( mBlueMaxLineEdit->text(), &blueMaxOk );
if ( blueMinOk && blueMaxOk && !mBlueAttributeComboBox->currentAttribute().isEmpty() )
{
blueEnhancement = new QgsContrastEnhancement( Qgis::UnknownDataType );
blueEnhancement->setMinimumValue( blueMin );
blueEnhancement->setMaximumValue( blueMax );
}
if ( redEnhancement )
{
redEnhancement->setContrastEnhancementAlgorithm( static_cast< QgsContrastEnhancement::ContrastEnhancementAlgorithm >(
( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ) ) );
}
if ( greenEnhancement )
{
greenEnhancement->setContrastEnhancementAlgorithm( static_cast< QgsContrastEnhancement::ContrastEnhancementAlgorithm >(
( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ) ) );
}
if ( blueEnhancement )
{
blueEnhancement->setContrastEnhancementAlgorithm( static_cast< QgsContrastEnhancement::ContrastEnhancementAlgorithm >(
( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ) ) );
}
symbol->setRedContrastEnhancement( redEnhancement );
symbol->setGreenContrastEnhancement( greenEnhancement );
symbol->setBlueContrastEnhancement( blueEnhancement );
}
void QgsPointCloud3DSymbolWidget::minMaxModified()
{
if ( !mDisableMinMaxWidgetRefresh )
{
if ( ( QgsContrastEnhancement::ContrastEnhancementAlgorithm )( mContrastEnhancementAlgorithmComboBox->currentData().toInt() ) == QgsContrastEnhancement::NoEnhancement )
{
mContrastEnhancementAlgorithmComboBox->setCurrentIndex(
mContrastEnhancementAlgorithmComboBox->findData( ( int ) QgsContrastEnhancement::StretchToMinimumMaximum ) );
}
emitChangedSignal();
}
}
void QgsPointCloud3DSymbolWidget::setMinMaxValue( const QgsContrastEnhancement *ce, QLineEdit *minEdit, QLineEdit *maxEdit )
{
if ( !minEdit || !maxEdit )
{
return;
}
if ( !ce )
{
minEdit->clear();
maxEdit->clear();
return;
}
minEdit->setText( QLocale().toString( ce->minimumValue() ) );
maxEdit->setText( QLocale().toString( ce->maximumValue() ) );
// QgsMultiBandColorRenderer is using individual contrast enhancements for each
// band, but this widget GUI has one for all
mContrastEnhancementAlgorithmComboBox->setCurrentIndex( mContrastEnhancementAlgorithmComboBox->findData(
static_cast< int >( ce->contrastEnhancementAlgorithm() ) ) );
}
void QgsPointCloud3DSymbolWidget::reloadColorRampShaderMinMax()
{
double min = mColorRampShaderMinEdit->value();
@ -179,7 +348,38 @@ void QgsPointCloud3DSymbolWidget::onRenderingStyleChanged()
{
const QgsPointCloudRgbRenderer *renderer2d = dynamic_cast< const QgsPointCloudRgbRenderer * >( mLayer->renderer() );
mBlockChangedSignals++;
// todo
if ( renderer2d )
{
mRedAttributeComboBox->setAttribute( renderer2d->redAttribute() );
mGreenAttributeComboBox->setAttribute( renderer2d->greenAttribute() );
mBlueAttributeComboBox->setAttribute( renderer2d->blueAttribute() );
mDisableMinMaxWidgetRefresh++;
setMinMaxValue( renderer2d->redContrastEnhancement(), mRedMinLineEdit, mRedMaxLineEdit );
setMinMaxValue( renderer2d->greenContrastEnhancement(), mGreenMinLineEdit, mGreenMaxLineEdit );
setMinMaxValue( renderer2d->blueContrastEnhancement(), mBlueMinLineEdit, mBlueMaxLineEdit );
mDisableMinMaxWidgetRefresh--;
}
else
{
if ( mRedAttributeComboBox->findText( QStringLiteral( "Red" ) ) > -1 && mRedAttributeComboBox->findText( QStringLiteral( "Green" ) ) > -1 &&
mRedAttributeComboBox->findText( QStringLiteral( "Blue" ) ) > -1 )
{
mRedAttributeComboBox->setAttribute( QStringLiteral( "Red" ) );
mGreenAttributeComboBox->setAttribute( QStringLiteral( "Green" ) );
mBlueAttributeComboBox->setAttribute( QStringLiteral( "Blue" ) );
}
else
{
mRedAttributeComboBox->setCurrentIndex( mRedAttributeComboBox->count() > 1 ? 1 : 0 );
mGreenAttributeComboBox->setCurrentIndex( mGreenAttributeComboBox->count() > 2 ? 2 : 0 );
mBlueAttributeComboBox->setCurrentIndex( mBlueAttributeComboBox->count() > 3 ? 3 : 0 );
}
redAttributeChanged();
greenAttributeChanged();
blueAttributeChanged();
}
( void )( renderer2d );
mBlockChangedSignals--;
}
@ -237,3 +437,93 @@ void QgsPointCloud3DSymbolWidget::minMaxChanged()
mColorRampShaderWidget->setMinimumMaximumAndClassify( mColorRampShaderMinEdit->value(), mColorRampShaderMaxEdit->value() );
}
void QgsPointCloud3DSymbolWidget::mRedMinLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsPointCloud3DSymbolWidget::mRedMaxLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsPointCloud3DSymbolWidget::mGreenMinLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsPointCloud3DSymbolWidget::mGreenMaxLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsPointCloud3DSymbolWidget::mBlueMinLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsPointCloud3DSymbolWidget::mBlueMaxLineEdit_textChanged( const QString & )
{
minMaxModified();
}
void QgsPointCloud3DSymbolWidget::redAttributeChanged()
{
if ( mLayer && mLayer->dataProvider() )
{
const QVariant max = mLayer->dataProvider()->metadataStatistic( mRedAttributeComboBox->currentAttribute(), QgsStatisticalSummary::Max );
if ( max.isValid() )
{
const int maxValue = max.toInt();
mDisableMinMaxWidgetRefresh++;
mRedMinLineEdit->setText( QLocale().toString( 0 ) );
// try and guess suitable range from input max values -- we don't just take the provider max value directly here, but rather see if it's
// likely to be 8 bit or 16 bit color values
mRedMaxLineEdit->setText( QLocale().toString( maxValue > 255 ? 65535 : 255 ) );
mDisableMinMaxWidgetRefresh--;
emitChangedSignal();
}
}
}
void QgsPointCloud3DSymbolWidget::greenAttributeChanged()
{
if ( mLayer && mLayer->dataProvider() )
{
const QVariant max = mLayer->dataProvider()->metadataStatistic( mGreenAttributeComboBox->currentAttribute(), QgsStatisticalSummary::Max );
if ( max.isValid() )
{
const int maxValue = max.toInt();
mDisableMinMaxWidgetRefresh++;
mGreenMinLineEdit->setText( QLocale().toString( 0 ) );
// try and guess suitable range from input max values -- we don't just take the provider max value directly here, but rather see if it's
// likely to be 8 bit or 16 bit color values
mGreenMaxLineEdit->setText( QLocale().toString( maxValue > 255 ? 65535 : 255 ) );
mDisableMinMaxWidgetRefresh--;
emitChangedSignal();
}
}
}
void QgsPointCloud3DSymbolWidget::blueAttributeChanged()
{
if ( mLayer && mLayer->dataProvider() )
{
const QVariant max = mLayer->dataProvider()->metadataStatistic( mBlueAttributeComboBox->currentAttribute(), QgsStatisticalSummary::Max );
if ( max.isValid() )
{
const int maxValue = max.toInt();
mDisableMinMaxWidgetRefresh++;
mBlueMinLineEdit->setText( QLocale().toString( 0 ) );
// try and guess suitable range from input max values -- we don't just take the provider max value directly here, but rather see if it's
// likely to be 8 bit or 16 bit color values
mBlueMaxLineEdit->setText( QLocale().toString( maxValue > 255 ? 65535 : 255 ) );
mDisableMinMaxWidgetRefresh--;
emitChangedSignal();
}
}
}

View File

@ -41,6 +41,16 @@ class QgsPointCloud3DSymbolWidget : public QWidget, private Ui::QgsPointCloud3DS
void setMinMaxFromLayer();
void minMaxChanged();
void mRedMinLineEdit_textChanged( const QString & );
void mRedMaxLineEdit_textChanged( const QString & );
void mGreenMinLineEdit_textChanged( const QString & );
void mGreenMaxLineEdit_textChanged( const QString & );
void mBlueMinLineEdit_textChanged( const QString & );
void mBlueMaxLineEdit_textChanged( const QString & );
void redAttributeChanged();
void greenAttributeChanged();
void blueAttributeChanged();
signals:
void changed();
@ -49,6 +59,7 @@ class QgsPointCloud3DSymbolWidget : public QWidget, private Ui::QgsPointCloud3DS
private:
int mBlockChangedSignals = 0;
int mDisableMinMaxWidgetRefresh = 0;
QgsPointCloudLayer *mLayer = nullptr;
bool mBlockMinMaxChanged = false;
@ -56,6 +67,11 @@ class QgsPointCloud3DSymbolWidget : public QWidget, private Ui::QgsPointCloud3DS
double mProviderMin = std::numeric_limits< double >::quiet_NaN();
double mProviderMax = std::numeric_limits< double >::quiet_NaN();
void createValidators();
void setCustomMinMaxValues( QgsRgbPointCloud3DSymbol *r ) const;
void minMaxModified();
void setMinMaxValue( const QgsContrastEnhancement *ce, QLineEdit *minEdit, QLineEdit *maxEdit );
};
#endif // QGSPOINTCLOUD3DSYMBOLWIDGET_H

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>549</width>
<height>484</height>
<width>563</width>
<height>464</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
@ -64,7 +64,7 @@
<item row="2" column="0" colspan="3">
<widget class="QStackedWidget" name="mStackedWidget">
<property name="currentIndex">
<number>3</number>
<number>0</number>
</property>
<widget class="QWidget" name="noRendererPage"/>
<widget class="QWidget" name="singleColorRendererPage">
@ -88,19 +88,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QgsColorButton" name="mSingleColorBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer_2">
<property name="orientation">
@ -114,10 +101,23 @@
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="QgsColorButton" name="mSingleColorBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="colorRampRendererPage">
<layout class="QGridLayout" name="gridLayout_3" rowstretch="0,0,1" columnstretch="0,1">
<layout class="QGridLayout" name="gridLayout_3" rowstretch="0,0,0" columnstretch="0,0">
<property name="leftMargin">
<number>0</number>
</property>
@ -140,6 +140,9 @@
<item row="0" column="1">
<widget class="QgsPointCloudAttributeComboBox" name="mRenderingParameterComboBox"/>
</item>
<item row="2" column="0" colspan="2">
<widget class="QgsColorRampShaderWidget" name="mColorRampShaderWidget" native="true"/>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0,1,0">
<item>
@ -197,12 +200,235 @@
</item>
</layout>
</item>
<item row="2" column="0" colspan="2">
<widget class="QgsColorRampShaderWidget" name="mColorRampShaderWidget" native="true"/>
</layout>
</widget>
<widget class="QWidget" name="rgbRendererPage">
<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>
<item>
<layout class="QGridLayout" name="gridLayout_4">
<item row="6" column="0">
<widget class="QLabel" name="mContrastEnhancementAlgorithmLabel">
<property name="text">
<string>Contrast
enhancement</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mRedBandLabel">
<property name="text">
<string>Red band</string>
</property>
</widget>
</item>
<item row="6" column="1" colspan="4">
<widget class="QComboBox" name="mContrastEnhancementAlgorithmComboBox"/>
</item>
<item row="1" column="1">
<widget class="QLabel" name="mRedMinLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Min</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="mRedMaxLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Max</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="mRedMinLineEdit">
<property name="maxLength">
<number>16</number>
</property>
</widget>
</item>
<item row="0" column="1" colspan="4">
<widget class="QgsPointCloudAttributeComboBox" name="mRedAttributeComboBox"/>
</item>
<item row="5" column="1">
<widget class="QLabel" name="mBlueMinLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Min</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="QLabel" name="mBlueMaxLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Max</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1" colspan="4">
<widget class="QgsPointCloudAttributeComboBox" name="mGreenAttributeComboBox"/>
</item>
<item row="3" column="1">
<widget class="QLabel" name="mGreenMinLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Min</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="mGreenMaxLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Max</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="1" colspan="4">
<widget class="QgsPointCloudAttributeComboBox" name="mBlueAttributeComboBox"/>
</item>
<item row="1" column="4">
<widget class="QLineEdit" name="mRedMaxLineEdit">
<property name="maxLength">
<number>16</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLineEdit" name="mGreenMinLineEdit">
<property name="maxLength">
<number>16</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="mBlueBandLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Blue band</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QLineEdit" name="mBlueMinLineEdit">
<property name="maxLength">
<number>16</number>
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QLineEdit" name="mBlueMaxLineEdit">
<property name="maxLength">
<number>16</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="mGreenBandLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Green band</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLineEdit" name="mGreenMaxLineEdit">
<property name="maxLength">
<number>16</number>
</property>
</widget>
</item>
</layout>
</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>
<widget class="QWidget" name="rgbRendererPage"/>
</widget>
</item>
<item row="1" column="0" colspan="3">