mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
[FEATURE] Add a generic numeric transform assistant for easy scaling of values
This commit is contained in:
parent
2df37a2313
commit
a30fe357f1
@ -32,6 +32,9 @@ QgsPropertyTransformer* QgsPropertyTransformer::create( QgsPropertyTransformer::
|
||||
QgsPropertyTransformer* transformer = nullptr;
|
||||
switch ( type )
|
||||
{
|
||||
case GenericNumericTransformer:
|
||||
transformer = new QgsGenericNumericTransformer();
|
||||
break;
|
||||
case SizeScaleTransformer:
|
||||
transformer = new QgsSizeScaleTransformer();
|
||||
break;
|
||||
@ -74,6 +77,172 @@ bool QgsPropertyTransformer::readXml( const QDomElement &transformerElem, const
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// QgsGenericNumericTransformer
|
||||
//
|
||||
|
||||
QgsGenericNumericTransformer::QgsGenericNumericTransformer( double minValue, double maxValue, double minOutput, double maxOutput, double nullOutput, double exponent )
|
||||
: QgsPropertyTransformer( minValue, maxValue )
|
||||
, mMinOutput( minOutput )
|
||||
, mMaxOutput( maxOutput )
|
||||
, mNullOutput( nullOutput )
|
||||
, mExponent( exponent )
|
||||
{}
|
||||
|
||||
QgsGenericNumericTransformer *QgsGenericNumericTransformer::clone()
|
||||
{
|
||||
return new QgsGenericNumericTransformer( mMinValue,
|
||||
mMaxValue,
|
||||
mMinOutput,
|
||||
mMaxOutput,
|
||||
mNullOutput,
|
||||
mExponent );
|
||||
}
|
||||
|
||||
bool QgsGenericNumericTransformer::writeXml( QDomElement &transformerElem, QDomDocument &doc ) const
|
||||
{
|
||||
if ( !QgsPropertyTransformer::writeXml( transformerElem, doc ) )
|
||||
return false;
|
||||
|
||||
transformerElem.setAttribute( "minOutput", QString::number( mMinOutput ) );
|
||||
transformerElem.setAttribute( "maxOutput", QString::number( mMaxOutput ) );
|
||||
transformerElem.setAttribute( "nullOutput", QString::number( mNullOutput ) );
|
||||
transformerElem.setAttribute( "exponent", QString::number( mExponent ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsGenericNumericTransformer::readXml( const QDomElement &transformerElem, const QDomDocument &doc )
|
||||
{
|
||||
if ( !QgsPropertyTransformer::readXml( transformerElem, doc ) )
|
||||
return false;
|
||||
|
||||
mMinOutput = transformerElem.attribute( "minOutput", "0.0" ).toDouble();
|
||||
mMaxOutput = transformerElem.attribute( "maxOutput", "1.0" ).toDouble();
|
||||
mNullOutput = transformerElem.attribute( "nullOutput", "0.0" ).toDouble();
|
||||
mExponent = transformerElem.attribute( "exponent", "1.0" ).toDouble();
|
||||
return true;
|
||||
}
|
||||
|
||||
double QgsGenericNumericTransformer::value( double input ) const
|
||||
{
|
||||
if ( qgsDoubleNear( mExponent, 1.0 ) )
|
||||
return mMinOutput + ( qBound( mMinValue, input, mMaxValue ) - mMinValue ) * ( mMaxOutput - mMinOutput ) / ( mMaxValue - mMinValue );
|
||||
else
|
||||
return mMinOutput + qPow( qBound( mMinValue, input, mMaxValue ) - mMinValue, mExponent ) * ( mMaxOutput - mMinOutput ) / qPow( mMaxValue - mMinValue, mExponent );
|
||||
}
|
||||
|
||||
QVariant QgsGenericNumericTransformer::transform( const QgsExpressionContext& context, const QVariant& v ) const
|
||||
{
|
||||
Q_UNUSED( context );
|
||||
|
||||
if ( v.isNull() )
|
||||
return mNullOutput;
|
||||
|
||||
bool ok;
|
||||
double dblValue = v.toDouble( &ok );
|
||||
|
||||
if ( ok )
|
||||
{
|
||||
//apply scaling to value
|
||||
return value( dblValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsGenericNumericTransformer::toExpression( const QString& baseExpression ) const
|
||||
{
|
||||
QString minValueString = QString::number( mMinValue );
|
||||
QString maxValueString = QString::number( mMaxValue );
|
||||
QString minOutputString = QString::number( mMinOutput );
|
||||
QString maxOutputString = QString::number( mMaxOutput );
|
||||
QString nullOutputString = QString::number( mNullOutput );
|
||||
QString exponentString = QString::number( mExponent );
|
||||
|
||||
if ( qgsDoubleNear( mExponent, 1.0 ) )
|
||||
return QStringLiteral( "coalesce(scale_linear(%1, %2, %3, %4, %5), %6)" ).arg( baseExpression, minValueString, maxValueString, minOutputString, maxOutputString, nullOutputString );
|
||||
else
|
||||
return QStringLiteral( "coalesce(scale_exp(%1, %2, %3, %4, %5, %6), %7)" ).arg( baseExpression, minValueString, maxValueString, minOutputString, maxOutputString, exponentString, nullOutputString );
|
||||
}
|
||||
|
||||
QgsGenericNumericTransformer* QgsGenericNumericTransformer::fromExpression( const QString& expression, QString& baseExpression, QString& fieldName )
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
double nullValue = 0.0;
|
||||
double exponent = 1.0;
|
||||
|
||||
baseExpression.clear();
|
||||
fieldName.clear();
|
||||
|
||||
QgsExpression e( expression );
|
||||
|
||||
if ( !e.rootNode() )
|
||||
return nullptr;
|
||||
|
||||
const QgsExpression::NodeFunction * f = dynamic_cast<const QgsExpression::NodeFunction*>( e.rootNode() );
|
||||
if ( !f )
|
||||
return nullptr;
|
||||
|
||||
QList<QgsExpression::Node*> args = f->args()->list();
|
||||
|
||||
// the scale function may be enclosed in a coalesce(expr, 0) to avoid NULL value
|
||||
// to be drawn with the default size
|
||||
if ( "coalesce" == QgsExpression::Functions()[f->fnIndex()]->name() )
|
||||
{
|
||||
f = dynamic_cast<const QgsExpression::NodeFunction*>( args[0] );
|
||||
if ( !f )
|
||||
return nullptr;
|
||||
nullValue = QgsExpression( args[1]->dump() ).evaluate().toDouble( &ok );
|
||||
if ( ! ok )
|
||||
return nullptr;
|
||||
args = f->args()->list();
|
||||
}
|
||||
|
||||
if ( "scale_linear" == QgsExpression::Functions()[f->fnIndex()]->name() )
|
||||
{
|
||||
exponent = 1.0;
|
||||
}
|
||||
else if ( "scale_exp" == QgsExpression::Functions()[f->fnIndex()]->name() )
|
||||
{
|
||||
exponent = QgsExpression( args[5]->dump() ).evaluate().toDouble( &ok );
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool expOk = true;
|
||||
double minValue = QgsExpression( args[1]->dump() ).evaluate().toDouble( &ok );
|
||||
expOk &= ok;
|
||||
double maxValue = QgsExpression( args[2]->dump() ).evaluate().toDouble( &ok );
|
||||
expOk &= ok;
|
||||
double minOutput = QgsExpression( args[3]->dump() ).evaluate().toDouble( &ok );
|
||||
expOk &= ok;
|
||||
double maxOutput = QgsExpression( args[4]->dump() ).evaluate().toDouble( &ok );
|
||||
expOk &= ok;
|
||||
|
||||
if ( !expOk )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( args[0]->nodeType() == QgsExpression::ntColumnRef )
|
||||
{
|
||||
fieldName = static_cast< QgsExpression::NodeColumnRef* >( args[0] )->name();
|
||||
}
|
||||
else
|
||||
{
|
||||
baseExpression = args[0]->dump();
|
||||
}
|
||||
return new QgsGenericNumericTransformer( minValue, maxValue, minOutput, maxOutput, nullValue, exponent );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// QgsSizeScaleProperty
|
||||
//
|
||||
@ -417,4 +586,3 @@ void QgsColorRampTransformer::setColorRamp( QgsColorRamp* ramp )
|
||||
{
|
||||
mGradientRamp.reset( ramp );
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ class CORE_EXPORT QgsPropertyTransformer
|
||||
//! Transformer types
|
||||
enum Type
|
||||
{
|
||||
GenericNumericTransformer, //!< Generic transformer for numeric values (QgsGenericNumericTransformer)
|
||||
SizeScaleTransformer, //!< Size scaling transformer (QgsSizeScaleTransformer)
|
||||
ColorRampTransformer, //!< Color ramp transformer (QgsColorRampTransformer)
|
||||
};
|
||||
@ -157,6 +158,124 @@ class CORE_EXPORT QgsPropertyTransformer
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \class QgsGenericNumericTransformer
|
||||
* \brief QgsPropertyTransformer subclass for scaling an input numeric value into an output numeric value.
|
||||
* \note Added in version 3.0
|
||||
*/
|
||||
|
||||
class CORE_EXPORT QgsGenericNumericTransformer : public QgsPropertyTransformer
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsGenericNumericTransformer.
|
||||
* @param minValue minimum expected input value
|
||||
* @param maxValue maximum expected input value
|
||||
* @param minOutput minimum value to return
|
||||
* @param maxOutput maximum value to return
|
||||
* @param nullOutput value to return for null inputs
|
||||
* @param exponent optional exponential for non-linear scaling
|
||||
*/
|
||||
QgsGenericNumericTransformer( double minValue = 0.0,
|
||||
double maxValue = 1.0,
|
||||
double minOutput = 0.0,
|
||||
double maxOutput = 1.0,
|
||||
double nullOutput = 0.0,
|
||||
double exponent = 1.0 );
|
||||
|
||||
virtual Type transformerType() const override { return GenericNumericTransformer; }
|
||||
virtual QgsGenericNumericTransformer* clone() override;
|
||||
virtual bool writeXml( QDomElement& transformerElem, QDomDocument& doc ) const override;
|
||||
virtual bool readXml( const QDomElement& transformerElem, const QDomDocument& doc ) override;
|
||||
virtual QVariant transform( const QgsExpressionContext& context, const QVariant& value ) const override;
|
||||
virtual QString toExpression( const QString& baseExpression ) const override;
|
||||
|
||||
/**
|
||||
* Attempts to parse an expression into a corresponding QgsSizeScaleTransformer.
|
||||
* @param expression expression to parse
|
||||
* @param baseExpression will be set to the component of the source expression which
|
||||
* is used to calculate the input to the property transformer. This will be set to an
|
||||
* empty string if a field reference is the transformer input.
|
||||
* @param fieldName will be set to a field name which is used to calculate the input
|
||||
* to the property transformer. This will be set to an
|
||||
* empty string if an expression is the transformer input.
|
||||
* @returns corresponding QgsSizeScaleTransformer, or nullptr if expression could not
|
||||
* be parsed to a size scale transformer.
|
||||
*/
|
||||
static QgsGenericNumericTransformer* fromExpression( const QString& expression, QString& baseExpression, QString& fieldName );
|
||||
|
||||
/**
|
||||
* Calculates the size corresponding to a specific value.
|
||||
* @param value value to calculate size for
|
||||
* @returns calculated size using size scale transformer's parameters and type
|
||||
*/
|
||||
double value( double input ) const;
|
||||
|
||||
/**
|
||||
* Returns the minimum calculated size.
|
||||
* @see setMinSize()
|
||||
* @see maxSize()
|
||||
*/
|
||||
double minOutputValue() const { return mMinOutput; }
|
||||
|
||||
/**
|
||||
* Sets the minimum calculated size.
|
||||
* @param size minimum size
|
||||
* @see minSize()
|
||||
* @see setMaxSize()
|
||||
*/
|
||||
void setMinOutputValue( double size ) { mMinOutput = size; }
|
||||
|
||||
/**
|
||||
* Returns the maximum calculated size.
|
||||
* @see minSize()
|
||||
*/
|
||||
double maxOutputValue() const { return mMaxOutput; }
|
||||
|
||||
/**
|
||||
* Sets the maximum calculated size.
|
||||
* @param size maximum size
|
||||
* @see maxSize()
|
||||
* @see setMinSize()
|
||||
*/
|
||||
void setMaxOutputValue( double size ) { mMaxOutput = size; }
|
||||
|
||||
/**
|
||||
* Returns the size value when an expression evaluates to NULL.
|
||||
* @see setNullSize()
|
||||
*/
|
||||
double nullOutputValue() const { return mNullOutput; }
|
||||
|
||||
/**
|
||||
* Sets the size value for when an expression evaluates to NULL.
|
||||
* @param size null size
|
||||
* @see nullSize()
|
||||
*/
|
||||
void setNullOutputValue( double size ) { mNullOutput = size; }
|
||||
|
||||
/**
|
||||
* Returns the exponent for an exponential expression.
|
||||
* @see setExponent()
|
||||
* @see type()
|
||||
*/
|
||||
double exponent() const { return mExponent; }
|
||||
|
||||
/**
|
||||
* Sets the exponent for an exponential expression.
|
||||
* @param exponent exponent
|
||||
* @see exponent()
|
||||
*/
|
||||
void setExponent( double exponent ) { mExponent = exponent; }
|
||||
|
||||
private:
|
||||
double mMinOutput;
|
||||
double mMaxOutput;
|
||||
double mNullOutput;
|
||||
double mExponent;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
|
@ -75,6 +75,7 @@ QgsPropertyAssistantWidget::QgsPropertyAssistantWidget( QWidget* parent ,
|
||||
case QgsPropertyDefinition::StrokeWidth:
|
||||
{
|
||||
mTransformerWidget = new QgsPropertySizeAssistantWidget( this, mDefinition, initialState );
|
||||
mLegendPreview->show();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -82,11 +83,18 @@ QgsPropertyAssistantWidget::QgsPropertyAssistantWidget( QWidget* parent ,
|
||||
case QgsPropertyDefinition::ColorWithAlpha:
|
||||
{
|
||||
mTransformerWidget = new QgsPropertyColorAssistantWidget( this, mDefinition, initialState );
|
||||
mLegendPreview->show();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
if ( mDefinition.dataType() == QgsPropertyDefinition::DataTypeNumeric )
|
||||
{
|
||||
mTransformerWidget = new QgsPropertyGenericNumericAssistantWidget( this, mDefinition, initialState );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( mTransformerWidget )
|
||||
@ -157,7 +165,7 @@ void QgsPropertyAssistantWidget::computeValuesFromLayer()
|
||||
|
||||
void QgsPropertyAssistantWidget::updatePreview()
|
||||
{
|
||||
if ( !mTransformerWidget || !mLayer ) // TODO - make this work OK without a layer
|
||||
if ( mLegendPreview->isHidden() || !mTransformerWidget || !mLayer ) // TODO - make this work OK without a layer
|
||||
return;
|
||||
|
||||
mLegendPreview->setIconSize( QSize( 512, 512 ) );
|
||||
@ -168,11 +176,6 @@ void QgsPropertyAssistantWidget::updatePreview()
|
||||
|
||||
QList< QgsSymbolLegendNode* > nodes = mTransformerWidget->generatePreviews( breaks, mLayerTreeLayer, mSymbol.get(), minValueSpinBox->value(),
|
||||
maxValueSpinBox->value() );
|
||||
if ( nodes.isEmpty() )
|
||||
{
|
||||
mLegendPreview->show();
|
||||
return;
|
||||
}
|
||||
|
||||
int widthMax = 0;
|
||||
int i = 0;
|
||||
@ -200,7 +203,6 @@ void QgsPropertyAssistantWidget::updatePreview()
|
||||
p.end();
|
||||
mPreviewList.item( i )->setIcon( enlarged );
|
||||
}
|
||||
mLegendPreview->show();
|
||||
}
|
||||
|
||||
bool QgsPropertyAssistantWidget::computeValuesFromExpression( const QString& expression, double& minValue, double& maxValue ) const
|
||||
@ -456,3 +458,41 @@ QList<QgsSymbolLegendNode*> QgsPropertyColorAssistantWidget::generatePreviews( c
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
QgsPropertyGenericNumericAssistantWidget::QgsPropertyGenericNumericAssistantWidget( QWidget* parent, const QgsPropertyDefinition& definition, const QgsProperty& initialState )
|
||||
: QgsPropertyAbstractTransformerWidget( parent, definition )
|
||||
{
|
||||
setupUi( this );
|
||||
|
||||
layout()->setContentsMargins( 0, 0, 0, 0 );
|
||||
layout()->setMargin( 0 );
|
||||
|
||||
minOutputSpinBox->setShowClearButton( false );
|
||||
maxOutputSpinBox->setShowClearButton( false );
|
||||
nullOutputSpinBox->setShowClearButton( false );
|
||||
|
||||
if ( const QgsGenericNumericTransformer* transform = dynamic_cast< const QgsGenericNumericTransformer* >( initialState.transformer() ) )
|
||||
{
|
||||
minOutputSpinBox->setValue( transform->minOutputValue() );
|
||||
maxOutputSpinBox->setValue( transform->maxOutputValue() );
|
||||
nullOutputSpinBox->setValue( transform->nullOutputValue() );
|
||||
exponentSpinBox->setValue( transform->exponent() );
|
||||
}
|
||||
|
||||
connect( minOutputSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertySizeAssistantWidget::widgetChanged );
|
||||
connect( maxOutputSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertySizeAssistantWidget::widgetChanged );
|
||||
connect( nullOutputSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertySizeAssistantWidget::widgetChanged );
|
||||
connect( exponentSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertySizeAssistantWidget::widgetChanged );
|
||||
}
|
||||
|
||||
QgsGenericNumericTransformer*QgsPropertyGenericNumericAssistantWidget::createTransformer( double minValue, double maxValue ) const
|
||||
{
|
||||
QgsGenericNumericTransformer* transformer = new QgsGenericNumericTransformer(
|
||||
minValue,
|
||||
maxValue,
|
||||
minOutputSpinBox->value(),
|
||||
maxOutputSpinBox->value(),
|
||||
nullOutputSpinBox->value(),
|
||||
exponentSpinBox->value() );
|
||||
return transformer;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "ui_qgspropertyassistantwidgetbase.h"
|
||||
#include "ui_qgspropertysizeassistantwidget.h"
|
||||
#include "ui_qgspropertycolorassistantwidget.h"
|
||||
#include "ui_qgspropertygenericnumericassistantwidget.h"
|
||||
#include "qgsproperty.h"
|
||||
#include "qgslayertreegroup.h"
|
||||
#include "qgssymbol.h"
|
||||
@ -59,6 +60,18 @@ class GUI_EXPORT QgsPropertyAbstractTransformerWidget : public QWidget
|
||||
|
||||
};
|
||||
|
||||
class GUI_EXPORT QgsPropertyGenericNumericAssistantWidget : public QgsPropertyAbstractTransformerWidget, private Ui::PropertyGenericNumericAssistant
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
QgsPropertyGenericNumericAssistantWidget( QWidget* parent = nullptr, const QgsPropertyDefinition& definition = QgsPropertyDefinition(), const QgsProperty& initialState = QgsProperty() );
|
||||
|
||||
virtual QgsGenericNumericTransformer* createTransformer( double minValue, double maxValue ) const override;
|
||||
|
||||
};
|
||||
|
||||
class GUI_EXPORT QgsPropertySizeAssistantWidget : public QgsPropertyAbstractTransformerWidget, private Ui::PropertySizeAssistant
|
||||
{
|
||||
Q_OBJECT
|
||||
|
127
src/ui/qgspropertygenericnumericassistantwidget.ui
Normal file
127
src/ui/qgspropertygenericnumericassistantwidget.ui
Normal file
@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PropertyGenericNumericAssistant</class>
|
||||
<widget class="QWidget" name="PropertyGenericNumericAssistant">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>288</width>
|
||||
<height>192</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0">
|
||||
<item row="1" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="maxOutputSpinBox">
|
||||
<property name="decimals">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>10.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Output from</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Output when NULL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Exponent</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="nullOutputSpinBox">
|
||||
<property name="decimals">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="exponentSpinBox">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>to</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QgsDoubleSpinBox" name="minOutputSpinBox">
|
||||
<property name="decimals">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>99999999.000000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<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>minOutputSpinBox</tabstop>
|
||||
<tabstop>maxOutputSpinBox</tabstop>
|
||||
<tabstop>exponentSpinBox</tabstop>
|
||||
<tabstop>nullOutputSpinBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -81,6 +81,8 @@ class TestQgsProperty : public QObject
|
||||
void equality();
|
||||
void propertyTransformer(); //test for QgsPropertyTransformer
|
||||
void propertyTransformerFromExpression(); // text converting expression into QgsPropertyTransformer
|
||||
void genericNumericTransformer();
|
||||
void genericNumericTransformerFromExpression(); // text converting expression to QgsGenericNumericTransformer
|
||||
void sizeScaleTransformer(); //test for QgsSizeScaleTransformer
|
||||
void sizeScaleTransformerFromExpression(); // text converting expression to QgsSizeScaleTransformer
|
||||
void colorRampTransformer(); //test for QgsColorRampTransformer
|
||||
@ -680,6 +682,173 @@ void TestQgsProperty::propertyTransformerFromExpression()
|
||||
QVERIFY( fieldName.isEmpty() );
|
||||
}
|
||||
|
||||
void TestQgsProperty::genericNumericTransformer()
|
||||
{
|
||||
QgsExpressionContext context;
|
||||
QgsGenericNumericTransformer t1( 10,
|
||||
20,
|
||||
100,
|
||||
200,
|
||||
-10,
|
||||
1.0 );
|
||||
QCOMPARE( t1.transformerType(), QgsPropertyTransformer::GenericNumericTransformer );
|
||||
QCOMPARE( t1.minValue(), 10.0 );
|
||||
QCOMPARE( t1.maxValue(), 20.0 );
|
||||
QCOMPARE( t1.minOutputValue(), 100.0 );
|
||||
QCOMPARE( t1.maxOutputValue(), 200.0 );
|
||||
QCOMPARE( t1.nullOutputValue(), -10.0 );
|
||||
QCOMPARE( t1.exponent(), 1.0 );
|
||||
|
||||
//transform
|
||||
QCOMPARE( t1.transform( context, 10 ).toInt(), 100 );
|
||||
QCOMPARE( t1.transform( context, 20 ).toInt(), 200 );
|
||||
//null value
|
||||
QCOMPARE( t1.transform( context, QVariant( QVariant::Double ) ).toInt(), -10 );
|
||||
//non numeric value
|
||||
QCOMPARE( t1.transform( context, QVariant( "ffff" ) ), QVariant( "ffff" ) );
|
||||
|
||||
//saving and restoring
|
||||
|
||||
//create a test dom element
|
||||
QDomImplementation DomImplementation;
|
||||
QDomDocumentType documentType =
|
||||
DomImplementation.createDocumentType(
|
||||
"qgis", "http://mrcc.com/qgis.dtd", "SYSTEM" );
|
||||
QDomDocument doc( documentType );
|
||||
|
||||
QgsGenericNumericTransformer t2( 15,
|
||||
25,
|
||||
150,
|
||||
250,
|
||||
-10,
|
||||
99 );
|
||||
|
||||
QDomElement element = doc.createElement( "xform" );
|
||||
QVERIFY( t2.writeXml( element, doc ) );
|
||||
QgsGenericNumericTransformer r1;
|
||||
QVERIFY( r1.readXml( element, doc ) );
|
||||
QCOMPARE( r1.minValue(), 15.0 );
|
||||
QCOMPARE( r1.maxValue(), 25.0 );
|
||||
QCOMPARE( r1.minOutputValue(), 150.0 );
|
||||
QCOMPARE( r1.maxOutputValue(), 250.0 );
|
||||
QCOMPARE( r1.nullOutputValue(), -10.0 );
|
||||
QCOMPARE( r1.exponent(), 99.0 );
|
||||
|
||||
// test cloning
|
||||
std::unique_ptr< QgsGenericNumericTransformer > r2( t2.clone() );
|
||||
QCOMPARE( r2->minValue(), 15.0 );
|
||||
QCOMPARE( r2->maxValue(), 25.0 );
|
||||
QCOMPARE( r2->minOutputValue(), 150.0 );
|
||||
QCOMPARE( r2->maxOutputValue(), 250.0 );
|
||||
QCOMPARE( r2->nullOutputValue(), -10.0 );
|
||||
QCOMPARE( r2->exponent(), 99.0 );
|
||||
|
||||
//test various min/max value/size and scaling methods
|
||||
|
||||
//getters and setters
|
||||
QgsGenericNumericTransformer t;
|
||||
t.setMinValue( 100 );
|
||||
QCOMPARE( t.minValue(), 100.0 );
|
||||
t.setMaxValue( 200 );
|
||||
QCOMPARE( t.maxValue(), 200.0 );
|
||||
t.setMinOutputValue( 10.0 );
|
||||
QCOMPARE( t.minOutputValue(), 10.0 );
|
||||
t.setMaxOutputValue( 20.0 );
|
||||
QCOMPARE( t.maxOutputValue(), 20.0 );
|
||||
t.setNullOutputValue( 1 );
|
||||
QCOMPARE( t.nullOutputValue(), 1.0 );
|
||||
t.setExponent( 2.5 );
|
||||
QCOMPARE( t.exponent(), 2.5 );
|
||||
|
||||
//test linear scaling
|
||||
t.setExponent( 1.0 );
|
||||
QCOMPARE( t.value( 100 ), 10.0 );
|
||||
QCOMPARE( t.value( 150 ), 15.0 );
|
||||
QCOMPARE( t.value( 200 ), 20.0 );
|
||||
//test exponential scaling
|
||||
t.setExponent( 1.5 );
|
||||
QCOMPARE( t.value( 100 ), 10.0 );
|
||||
QVERIFY( qgsDoubleNear( t.value( 150 ), 13.5355, 0.001 ) );
|
||||
QCOMPARE( t.value( 200 ), 20.0 );
|
||||
|
||||
//as expression
|
||||
QgsGenericNumericTransformer t3( 15,
|
||||
25,
|
||||
150,
|
||||
250,
|
||||
-10,
|
||||
1.0 );
|
||||
QCOMPARE( t3.toExpression( "5+6" ), QStringLiteral( "coalesce(scale_linear(5+6, 15, 25, 150, 250), -10)" ) );
|
||||
t3.setExponent( 1.6 );
|
||||
QCOMPARE( t3.toExpression( "5+6" ), QStringLiteral( "coalesce(scale_exp(5+6, 15, 25, 150, 250, 1.6), -10)" ) );
|
||||
|
||||
// test size scale transformer inside property
|
||||
QgsProperty p;
|
||||
p.setTransformer( new QgsGenericNumericTransformer( 15,
|
||||
25,
|
||||
150,
|
||||
250,
|
||||
-10,
|
||||
99 ) );
|
||||
p.setStaticValue( QVariant() );
|
||||
bool ok = false;
|
||||
QCOMPARE( p.valueAsDouble( context, 100, &ok ), -10.0 );
|
||||
QVERIFY( ok );
|
||||
p.setExpressionString( QStringLiteral( "NULL" ) );
|
||||
QCOMPARE( p.valueAsDouble( context, 100, &ok ), -10.0 );
|
||||
QVERIFY( ok );
|
||||
p.setExpressionString( QStringLiteral( "no field" ) );
|
||||
QCOMPARE( p.valueAsDouble( context, 100, &ok ), -10.0 );
|
||||
QVERIFY( ok );
|
||||
}
|
||||
|
||||
void TestQgsProperty::genericNumericTransformerFromExpression()
|
||||
{
|
||||
QString baseExpression;
|
||||
QString fieldName;
|
||||
std::unique_ptr< QgsGenericNumericTransformer > exp( QgsGenericNumericTransformer::fromExpression( QStringLiteral( "coalesce(scale_linear(column, 1, 7, 2, 10), 0)" ), baseExpression, fieldName ) );
|
||||
QVERIFY( exp.get() );
|
||||
QCOMPARE( fieldName, QStringLiteral( "column" ) );
|
||||
QVERIFY( baseExpression.isEmpty() );
|
||||
QCOMPARE( exp->minValue(), 1. );
|
||||
QCOMPARE( exp->maxValue(), 7. );
|
||||
QCOMPARE( exp->minOutputValue(), 2. );
|
||||
QCOMPARE( exp->maxOutputValue(), 10. );
|
||||
QCOMPARE( exp->nullOutputValue(), 0.0 );
|
||||
|
||||
exp.reset( QgsGenericNumericTransformer::fromExpression( QStringLiteral( "scale_linear(column, 1, 7, 2, 10)" ), baseExpression, fieldName ) );
|
||||
QVERIFY( exp.get() );
|
||||
QCOMPARE( fieldName, QStringLiteral( "column" ) );
|
||||
QVERIFY( baseExpression.isEmpty() );
|
||||
QCOMPARE( exp->minValue(), 1. );
|
||||
QCOMPARE( exp->maxValue(), 7. );
|
||||
QCOMPARE( exp->minOutputValue(), 2. );
|
||||
QCOMPARE( exp->maxOutputValue(), 10. );
|
||||
|
||||
exp.reset( QgsGenericNumericTransformer::fromExpression( QStringLiteral( "scale_linear(column * 2, 1, 7, 2, 10)" ), baseExpression, fieldName ) );
|
||||
QVERIFY( exp.get() );
|
||||
QCOMPARE( baseExpression, QStringLiteral( "column * 2" ) );
|
||||
QVERIFY( fieldName.isEmpty() );
|
||||
QCOMPARE( exp->minValue(), 1. );
|
||||
QCOMPARE( exp->maxValue(), 7. );
|
||||
QCOMPARE( exp->minOutputValue(), 2. );
|
||||
QCOMPARE( exp->maxOutputValue(), 10. );
|
||||
|
||||
exp.reset( QgsGenericNumericTransformer::fromExpression( QStringLiteral( "coalesce(scale_exp(column, 1, 7, 2, 10, 0.51), 1)" ), baseExpression, fieldName ) );
|
||||
QVERIFY( exp.get() );
|
||||
QCOMPARE( exp->minValue(), 1. );
|
||||
QCOMPARE( exp->maxValue(), 7. );
|
||||
QCOMPARE( exp->minOutputValue(), 2. );
|
||||
QCOMPARE( exp->maxOutputValue(), 10. );
|
||||
QCOMPARE( exp->exponent(), 0.51 );
|
||||
QCOMPARE( exp->nullOutputValue(), 1.0 );
|
||||
|
||||
QVERIFY( !QgsGenericNumericTransformer::fromExpression( QStringLiteral( "coalesce(scale_exp(column, 1, 7, a, 10, 0.5), 0)" ), baseExpression, fieldName ) );
|
||||
QVERIFY( !QgsGenericNumericTransformer::fromExpression( QStringLiteral( "coalesce(scale_exp(column, 1, 7), 0)" ), baseExpression, fieldName ) );
|
||||
QVERIFY( !QgsGenericNumericTransformer::fromExpression( QStringLiteral( "1+2" ), baseExpression, fieldName ) );
|
||||
QVERIFY( !QgsGenericNumericTransformer::fromExpression( QStringLiteral( "" ), baseExpression, fieldName ) );
|
||||
}
|
||||
|
||||
void TestQgsProperty::sizeScaleTransformer()
|
||||
{
|
||||
QgsExpressionContext context;
|
||||
@ -842,6 +1011,7 @@ void TestQgsProperty::sizeScaleTransformerFromExpression()
|
||||
QCOMPARE( exp->maxValue(), 7. );
|
||||
QCOMPARE( exp->minSize(), 2. );
|
||||
QCOMPARE( exp->maxSize(), 10. );
|
||||
QCOMPARE( exp->nullSize(), 0.0 );
|
||||
|
||||
exp.reset( QgsSizeScaleTransformer::fromExpression( QStringLiteral( "coalesce(scale_exp(column, 1, 7, 2, 10, 0.5), 0)" ), baseExpression, fieldName ) );
|
||||
QVERIFY( exp.get() );
|
||||
@ -879,9 +1049,10 @@ void TestQgsProperty::sizeScaleTransformerFromExpression()
|
||||
QVERIFY( exp.get() );
|
||||
QCOMPARE( exp->type(), QgsSizeScaleTransformer::Flannery );
|
||||
|
||||
exp.reset( QgsSizeScaleTransformer::fromExpression( QStringLiteral( "coalesce(scale_exp(column, 1, 7, 2, 10, 0.51), 0)" ), baseExpression, fieldName ) );
|
||||
exp.reset( QgsSizeScaleTransformer::fromExpression( QStringLiteral( "coalesce(scale_exp(column, 1, 7, 2, 10, 0.51), 22)" ), baseExpression, fieldName ) );
|
||||
QVERIFY( exp.get() );
|
||||
QCOMPARE( exp->type(), QgsSizeScaleTransformer::Exponential );
|
||||
QCOMPARE( exp->nullSize(), 22.0 );
|
||||
|
||||
QVERIFY( !QgsSizeScaleTransformer::fromExpression( QStringLiteral( "coalesce(scale_exp(column, 1, 7, a, 10, 0.5), 0)" ), baseExpression, fieldName ) );
|
||||
QVERIFY( !QgsSizeScaleTransformer::fromExpression( QStringLiteral( "coalesce(scale_exp(column, 1, 7), 0)" ), baseExpression, fieldName ) );
|
||||
|
Loading…
x
Reference in New Issue
Block a user