Formatting and code cleanups for QgsScaleExpression

This commit is contained in:
Nyall Dawson 2015-04-30 06:26:20 +10:00
parent 70b91b6302
commit 721d9f5908
5 changed files with 277 additions and 123 deletions

View File

@ -97,6 +97,7 @@
%Include qgsrendercontext.sip
%Include qgsrunprocess.sip
%Include qgsscalecalculator.sip
%Include qgsscaleexpression.sip
%Include qgsscaleutils.sip
%Include qgssimplifymethod.sip
%Include qgssnapper.sip

View File

@ -0,0 +1,82 @@
/** \ingroup core
* \class QgsScaleExpression
* \brief Class storing parameters of a scale expression, which is a subclass of
* QgsExpression for expressions which return a size or width.
* \note Added in version 2.9
*/
class QgsScaleExpression : QgsExpression
{
%TypeHeaderCode
#include <qgsscaleexpression.h>
%End
public:
enum Type
{
Linear,
Area,
Flannery,
Unknown
};
/** Constructor for QgsScaleExpression which parses an expression string
* to determine whether it's a scale expression
* @param expression expression string
*/
QgsScaleExpression( const QString &expression );
/** Constructor for QgsScaleExpression which creates an expression from
* specified parameters
* @param type scale method
* @param baseExpression expression (or field) used for value
* @param minValue minimum value, corresponds to specified minimum size
* @param maxValue maximum value, corresponds to specified maximum size
* @param minSize minimum size
* @param maxSize maximum size
*/
QgsScaleExpression( Type type, const QString& baseExpression, double minValue, double maxValue, double minSize, double maxSize );
operator bool() const;
/** Calculates the size corresponding to a specific value.
* @param value
* @returns calculated size using expression's parameters and type
*/
double size( double value ) const;
/** Returns the minimum size calculated by the expression
* @see maxSize
*/
double minSize() const;
/** Returns the maximum size calculated by the expression
* @see minSize
*/
double maxSize() const;
/** Returns the minimum value expected by the expression. The minimum
* value corresponds to the expression's minimum size.
* @see maxValue
*/
double minValue() const;
/** Returns the maximum value expected by the expression. The maximum
* value corresponds to the expression's maximum size.
* @see minValue
*/
double maxValue() const;
/** Returns the base expression string (or field reference) used for
* calculating the values to be mapped to a size.
*/
QString baseExpression() const;
/** Returns the scale expression's type (method used to calculate
* the size from a value).
*/
Type type() const;
};

View File

@ -1,9 +1,8 @@
/***************************************************************************
qgsscaleexpression.cpp
---------------------
begin : November 2015
copyright : (C) 2015 by Vincent Mora
begin : November 2014
copyright : (C) 2014 by Vincent Mora
email : vincent dor mora at oslandia dot com
***************************************************************************
* *
@ -15,90 +14,127 @@
***************************************************************************/
#include "qgsscaleexpression.h"
#include "qgis.h"
#include <QStringList>
#include <qmath.h>
QgsScaleExpression::QgsScaleExpression( const QString& expression )
: QgsExpression( expression )
, mType( Unknown )
, mMinSize( 0 )
, mMaxSize( 10 )
, mMinValue( 0 )
, mMaxValue( 100 )
{
init();
}
QgsScaleExpression::QgsScaleExpression( Type type, const QString& baseExpression, double minValue, double maxValue, double minSize, double maxSize )
: QgsExpression( createExpression( type, baseExpression, minValue, maxValue, minSize, maxSize ) )
, mExpression( baseExpression )
, mType( type )
, mMinSize( minSize )
, mMaxSize( maxSize )
, mMinValue( minValue )
, mMaxValue( maxValue )
{
}
void QgsScaleExpression::init()
{
bool ok;
if ( rootNode() )
if ( !rootNode() )
return;
const NodeFunction * f = dynamic_cast<const NodeFunction*>( rootNode() );
if ( !f )
return;
QList<Node*> args = f->args()->list();
if ( "scale_linear" == Functions()[f->fnIndex()]->name() )
{
const NodeFunction * f = dynamic_cast<const NodeFunction*>( rootNode() );
if ( f )
mType = Linear;
}
else if ( "scale_exp" == Functions()[f->fnIndex()]->name() )
{
const double exp = QgsExpression( args[5]->dump() ).evaluate().toDouble( &ok );
if ( ! ok )
return;
if ( qgsDoubleNear( exp, 0.57, 0.001 ) )
mType = Flannery;
else if ( qgsDoubleNear( exp, 0.5, 0.001 ) )
mType = Area;
else
{
QList<Node*> args = f->args()->list();
if ( "scale_linear" == Functions()[f->fnIndex()]->name() )
{
mType = Linear;
}
if ( "scale_exp" == Functions()[f->fnIndex()]->name() )
{
const double exp = QgsExpression( args[5]->dump() ).evaluate().toDouble( &ok );
if ( ! ok ) return;
if ( qAbs( exp - .57 ) < .001 ) mType = Flannery;
else if ( qAbs( exp - .5 ) < .001 ) mType = Area;
else return;
}
mMinValue = QgsExpression( args[1]->dump() ).evaluate().toDouble( &ok );
if ( ! ok ) return;
mMaxValue = QgsExpression( args[2]->dump() ).evaluate().toDouble( &ok );
if ( ! ok ) return;
mMinSize = QgsExpression( args[3]->dump() ).evaluate().toDouble( &ok );
if ( ! ok ) return;
mMaxSize = QgsExpression( args[4]->dump() ).evaluate().toDouble( &ok );
if ( ! ok ) return;
mExpression = args[0]->dump();
mType = Unknown;
return;
}
}
}
else
{
mType = Unknown;
return;
}
QgsScaleExpression::QgsScaleExpression( const QString & expr )
: QgsExpression( expr )
{
init();
}
bool expOk = true;
mMinValue = QgsExpression( args[1]->dump() ).evaluate().toDouble( &ok );
expOk &= ok;
mMaxValue = QgsExpression( args[2]->dump() ).evaluate().toDouble( &ok );
expOk &= ok;
mMinSize = QgsExpression( args[3]->dump() ).evaluate().toDouble( &ok );
expOk &= ok;
mMaxSize = QgsExpression( args[4]->dump() ).evaluate().toDouble( &ok );
expOk &= ok;
QgsScaleExpression::QgsScaleExpression( Type type, const QString & baseExpr, double minValue, double maxValue, double minSize, double maxSize )
: QgsExpression( createExpression( type, baseExpr, minValue, maxValue, minSize, maxSize ) )
{
init();
if ( !expOk )
{
mType = Unknown;
return;
}
mExpression = args[0]->dump();
}
QString QgsScaleExpression::createExpression( Type type, const QString & baseExpr, double minValue, double maxValue, double minSize, double maxSize )
{
QString minValueString = QString::number( minValue );
QString maxValueString = QString::number( maxValue );
QString minSizeString = QString::number( minSize );
QString maxSizeString = QString::number( maxSize );
switch ( type )
{
case Linear:
return "scale_linear(" + baseExpr
+ ", " + QString::number( minValue )
+ ", " + QString::number( maxValue )
+ ", " + QString::number( minSize )
+ ", " + QString::number( maxSize ) + ")";
case Area:
return "scale_exp(" + baseExpr
+ ", " + QString::number( minValue )
+ ", " + QString::number( maxValue )
+ ", " + QString::number( minSize )
+ ", " + QString::number( maxSize ) + ", .5)";
case Flannery:
return "scale_exp(" + baseExpr
+ ", " + QString::number( minValue )
+ ", " + QString::number( maxValue )
+ ", " + QString::number( minSize )
+ ", " + QString::number( maxSize ) + ", .57)";
}
return "";
}
return QString( "scale_linear(%1,%2,%3,%4,%5)" ).arg( baseExpr, minValueString, maxValueString, minSizeString, maxSizeString );
case Area:
return QString( "scale_exp(%1,%2,%3,%4,%5, 0.5)" ).arg( baseExpr, minValueString, maxValueString, minSizeString, maxSizeString );
case Flannery:
return QString( "scale_exp(%1,%2,%3,%4,%5, 0.57)" ).arg( baseExpr, minValueString, maxValueString, minSizeString, maxSizeString );
case Unknown:
break;
}
return QString();
}
double QgsScaleExpression::size( double value ) const
{
switch ( mType )
{
case Linear: return mMinSize + ( qBound( mMinValue, value, mMaxValue ) - mMinValue ) * ( mMaxSize - mMinSize ) / ( mMaxValue - mMinValue );
case Area: return qPow( qBound( mMinValue, value, mMaxValue ) - mMinValue, .5 ) * ( mMaxSize - mMinSize ) / qPow( mMaxValue - mMinValue, .5 );
case Flannery: return qPow( qBound( mMinValue, value, mMaxValue ) - mMinValue, .57 ) * ( mMaxSize - mMinSize ) / qPow( mMaxValue - mMinValue, .57 );
case Linear:
return mMinSize + ( qBound( mMinValue, value, mMaxValue ) - mMinValue ) * ( mMaxSize - mMinSize ) / ( mMaxValue - mMinValue );
case Area:
return mMinSize + qPow( qBound( mMinValue, value, mMaxValue ) - mMinValue, .5 ) * ( mMaxSize - mMinSize ) / qPow( mMaxValue - mMinValue, .5 );
case Flannery:
return mMinSize + qPow( qBound( mMinValue, value, mMaxValue ) - mMinValue, .57 ) * ( mMaxSize - mMinSize ) / qPow( mMaxValue - mMinValue, .57 );
case Unknown:
break;
}
return 0;
}

View File

@ -1,9 +1,8 @@
/***************************************************************************
qgsscaleexpression.h
---------------------
begin : November 2015
copyright : (C) 2015 by Vincent Mora
begin : November 2014
copyright : (C) 2014 by Vincent Mora
email : vincent dor mora at oslandia dot com
***************************************************************************
* *
@ -13,47 +12,98 @@
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSSCALEEXPRESSION_H
#define QGSSCALEEXPRESSION_H
#include "qgsexpression.h"
//! Class to retrieve parameters of a
//! scale expression (size or width)
//!
//! It derives from QgsExpression,
/** \ingroup core
* \class QgsScaleExpression
* \brief Class storing parameters of a scale expression, which is a subclass of
* QgsExpression for expressions which return a size or width.
* \note Added in version 2.9
*/
class QgsScaleExpression: public QgsExpression
{
public:
enum Type {Linear, Area, Flannery};
public:
//! parse string like an expression and
//! detemine if it's a size expression
QgsScaleExpression( const QString & expr );
enum Type
{
Linear,
Area,
Flannery,
Unknown
};
//! setup expression from parameters
QgsScaleExpression( Type type, const QString & baseExpr, double minValue, double maxValue, double minSize, double maxSize );
/** Constructor for QgsScaleExpression which parses an expression string
* to determine whether it's a scale expression
* @param expression expression string
*/
QgsScaleExpression( const QString &expression );
operator bool() const { return ! mExpression.isEmpty(); }
double size( double value ) const;
/** Constructor for QgsScaleExpression which creates an expression from
* specified parameters
* @param type scale method
* @param baseExpression expression (or field) used for value
* @param minValue minimum value, corresponds to specified minimum size
* @param maxValue maximum value, corresponds to specified maximum size
* @param minSize minimum size
* @param maxSize maximum size
*/
QgsScaleExpression( Type type, const QString& baseExpression, double minValue, double maxValue, double minSize, double maxSize );
double minSize() const { return mMinSize; }
double maxSize() const { return mMaxSize; }
double minValue() const { return mMinValue; }
double maxValue() const { return mMaxValue; }
QString baseExpression() const { return mExpression; }
Type type() const { return mType; }
operator bool() const { return ! mExpression.isEmpty(); }
private:
QString mExpression;
Type mType;
double mMinSize;
double mMaxSize;
double mMinValue;
double mMaxValue;
/** Calculates the size corresponding to a specific value.
* @param value
* @returns calculated size using expression's parameters and type
*/
double size( double value ) const;
void init();
static QString createExpression( Type type, const QString & baseExpr, double minValue, double maxValue, double minSize, double maxSize );
/** Returns the minimum size calculated by the expression
* @see maxSize
*/
double minSize() const { return mMinSize; }
/** Returns the maximum size calculated by the expression
* @see minSize
*/
double maxSize() const { return mMaxSize; }
/** Returns the minimum value expected by the expression. The minimum
* value corresponds to the expression's minimum size.
* @see maxValue
*/
double minValue() const { return mMinValue; }
/** Returns the maximum value expected by the expression. The maximum
* value corresponds to the expression's maximum size.
* @see minValue
*/
double maxValue() const { return mMaxValue; }
/** Returns the base expression string (or field reference) used for
* calculating the values to be mapped to a size.
*/
QString baseExpression() const { return mExpression; }
/** Returns the scale expression's type (method used to calculate
* the size from a value).
*/
Type type() const { return mType; }
private:
QString mExpression;
Type mType;
double mMinSize;
double mMaxSize;
double mMinValue;
double mMaxValue;
void init();
static QString createExpression( Type type, const QString& baseExpr, double minValue, double maxValue, double minSize, double maxSize );
};

View File

@ -1,9 +1,9 @@
/***************************************************************************
test_template.cpp
--------------------------------------
Date : Sun Sep 16 12:22:23 AKDT 2007
Copyright : (C) 2007 by Gary E. Sherman
Email : sherman at mrcc dot com
testqgsscaleexpression.cpp
--------------------------
begin : November 2014
copyright : (C) 2014 by Vincent Mora
email : vincent dor mora at oslandia dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
@ -12,20 +12,13 @@
* (at your option) any later version. *
* *
***************************************************************************/
#include <QtTest/QtTest>
#include <QObject>
#include <QString>
#include <QObject>
#include <QtConcurrentMap>
#include <QSharedPointer>
#include <qgsapplication.h>
//header for class being tested
#include <qgsscaleexpression.h>
#include <qgsfeature.h>
#include <qgsfeaturerequest.h>
#include <qgsgeometry.h>
#include <qgsrenderchecker.h>
#if QT_VERSION < 0x40701
// See http://hub.qgis.org/issues/4284
@ -37,23 +30,8 @@ class TestQgsScaleExpression: public QObject
Q_OBJECT
private slots:
void initTestCase()
{
//
// Runs once before any tests are run
//
// init QGIS's paths - true means that all path will be inited from prefix
QgsApplication::init();
QgsApplication::initQgis();
// Will make sure the settings dir with the style file for color ramp is created
QgsApplication::createDB();
QgsApplication::showSettings();
}
void cleanupTestCase()
{
QgsApplication::exitQgis();
}
void initTestCase() {}
void cleanupTestCase() {}
void parsing()
{
@ -80,11 +58,18 @@ class TestQgsScaleExpression: public QObject
{
QgsScaleExpression exp( "scale_exp(column, 1, 7, 2, 10, 0.51)" );
QCOMPARE( bool(exp), false );
QCOMPARE( exp.type(), QgsScaleExpression::Unknown );
}
{
QgsScaleExpression exp( "scale_exp(column, 1, 7, a, 10, 0.5)" );
QCOMPARE( bool(exp), false );
QCOMPARE( exp.type(), QgsScaleExpression::Unknown );
}
{
QgsScaleExpression exp( "scale_exp(column, 1, 7)" );
QCOMPARE( bool(exp), false );
QCOMPARE( exp.type(), QgsScaleExpression::Unknown );
}
{
QgsScaleExpression exp( QgsScaleExpression::Linear, "column", 1, 7, 2, 10 );
QCOMPARE( bool(exp), true );