[FEATURE] Add a generic numeric transform assistant for easy scaling of values

This commit is contained in:
Nyall Dawson 2017-02-13 14:48:08 +10:00
parent 2df37a2313
commit a30fe357f1
6 changed files with 647 additions and 9 deletions

View File

@ -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 );
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View 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>

View File

@ -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 ) );