Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add API call for setting preferred distance unit for QgsExpression
  • Loading branch information
nyalldawson committed Feb 13, 2016
1 parent 99e52af commit 9f772bc
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 10 deletions.
15 changes: 15 additions & 0 deletions python/core/qgsexpression.sip
Expand Up @@ -139,6 +139,7 @@ class QgsExpression
/** Return calculator used for distance and area calculations
* (used by $length, $area and $perimeter functions only)
* @see setGeomCalculator()
* @see distanceUnits()
*/
QgsDistanceArea *geomCalculator();

Expand All @@ -150,6 +151,20 @@ class QgsExpression
*/
void setGeomCalculator( const QgsDistanceArea &calc );

/** Returns the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perimeter".
* @note distances are only converted when a geomCalculator() has been set
* @note added in QGIS 2.14
* @see setDistanceUnits()
*/
QGis::UnitType distanceUnits() const;

/** Sets the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perimeter".
* @note distances are only converted when a geomCalculator() has been set
* @note added in QGIS 2.14
* @see distanceUnits()
*/
void setDistanceUnits( QGis::UnitType unit );

/** This function currently replaces each expression between [% and %]
in the string with the result of its evaluation on the feature
passed as argument.
Expand Down
18 changes: 16 additions & 2 deletions src/core/qgsexpression.cpp
Expand Up @@ -1685,7 +1685,9 @@ static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext*
QgsDistanceArea* calc = parent->geomCalculator();
if ( calc )
{
return QVariant( calc->measureLength( f.constGeometry() ) );
double len = calc->measureLength( f.constGeometry() );
len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
return QVariant( len );
}
else
{
Expand All @@ -1700,7 +1702,9 @@ static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContex
QgsDistanceArea* calc = parent->geomCalculator();
if ( calc )
{
return QVariant( calc->measurePerimeter( f.constGeometry() ) );
double len = calc->measurePerimeter( f.constGeometry() );
len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
return QVariant( len );
}
else
{
Expand Down Expand Up @@ -3411,6 +3415,16 @@ QgsDistanceArea* QgsExpression::geomCalculator()
return d->mCalc.data();
}

QGis::UnitType QgsExpression::distanceUnits() const
{
return d->mDistanceUnit;
}

void QgsExpression::setDistanceUnits( QGis::UnitType unit )
{
d->mDistanceUnit = unit;
}

void QgsExpression::acceptVisitor( QgsExpression::Visitor& v ) const
{
if ( d->mRootNode )
Expand Down
15 changes: 15 additions & 0 deletions src/core/qgsexpression.h
Expand Up @@ -278,6 +278,7 @@ class CORE_EXPORT QgsExpression
/** Return calculator used for distance and area calculations
* (used by $length, $area and $perimeter functions only)
* @see setGeomCalculator()
* @see distanceUnits()
*/
QgsDistanceArea* geomCalculator();

Expand All @@ -290,6 +291,20 @@ class CORE_EXPORT QgsExpression
//TODO QGIS 3.0 change calc to a pointer, so that calculator can be cleared by passing nullptr
void setGeomCalculator( const QgsDistanceArea &calc );

/** Returns the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perimeter".
* @note distances are only converted when a geomCalculator() has been set
* @note added in QGIS 2.14
* @see setDistanceUnits()
*/
QGis::UnitType distanceUnits() const;

/** Sets the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perimeter".
* @note distances are only converted when a geomCalculator() has been set
* @note added in QGIS 2.14
* @see distanceUnits()
*/
void setDistanceUnits( QGis::UnitType unit );

/** This function currently replaces each expression between [% and %]
in the string with the result of its evaluation on the feature
passed as argument.
Expand Down
3 changes: 3 additions & 0 deletions src/core/qgsexpressionprivate.h
Expand Up @@ -38,6 +38,7 @@ class QgsExpressionPrivate
, mRowNumber( 0 )
, mScale( 0 )
, mCalc( nullptr )
, mDistanceUnit( QGis::UnknownUnit )
{}

QgsExpressionPrivate( const QgsExpressionPrivate& other )
Expand All @@ -48,6 +49,7 @@ class QgsExpressionPrivate
, mScale( other.mScale )
, mExp( other.mExp )
, mCalc( other.mCalc )
, mDistanceUnit( other.mDistanceUnit )
{}

~QgsExpressionPrivate()
Expand All @@ -67,6 +69,7 @@ class QgsExpressionPrivate
QString mExp;

QSharedPointer<QgsDistanceArea> mCalc;
QGis::UnitType mDistanceUnit;
};
///@endcond

Expand Down
58 changes: 50 additions & 8 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -1327,12 +1327,33 @@ class TestQgsExpression: public QObject
// test perimeter without geomCalculator
QgsExpression expPerimeter( "$perimeter" );
QVariant vPerimeter = expPerimeter.evaluate( &context );
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), 128282.086, 0.001 ) );
double expected = 128282.086;
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
// units should not be converted if no geometry calculator set
expPerimeter.setDistanceUnits( QGis::Feet );
vPerimeter = expPerimeter.evaluate( &context );
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
expPerimeter.setDistanceUnits( QGis::NauticalMiles );
vPerimeter = expPerimeter.evaluate( &context );
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );

// test perimeter with geomCalculator
expPerimeter.setGeomCalculator( da );
vPerimeter = expPerimeter.evaluate( &context );
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), 128289.074, 0.001 ) );
QgsExpression expPerimeter2( "$perimeter" );
expPerimeter2.setGeomCalculator( da );
vPerimeter = expPerimeter2.evaluate( &context );
expected = 128289.074;
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
// test unit conversion
expPerimeter2.setDistanceUnits( QGis::Meters ); //default units should be meters
vPerimeter = expPerimeter2.evaluate( &context );
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
expPerimeter2.setDistanceUnits( QGis::UnknownUnit ); //unknown units should not be converted
vPerimeter = expPerimeter2.evaluate( &context );
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
expPerimeter2.setDistanceUnits( QGis::Feet );
expected = 420895.9120735;
vPerimeter = expPerimeter2.evaluate( &context );
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );

// test length without geomCalculator
QgsPolyline line3111;
Expand All @@ -1342,12 +1363,33 @@ class TestQgsExpression: public QObject

QgsExpression expLength( "$length" );
QVariant vLength = expLength.evaluate( &context );
QVERIFY( qgsDoubleNear( vLength.toDouble(), 26930.637, 0.001 ) );
expected = 26930.637;
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
// units should not be converted if no geometry calculator set
expLength.setDistanceUnits( QGis::Feet );
vLength = expLength.evaluate( &context );
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
expLength.setDistanceUnits( QGis::NauticalMiles );
vLength = expLength.evaluate( &context );
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );

// test length with geomCalculator
expLength.setGeomCalculator( da );
vLength = expLength.evaluate( &context );
QVERIFY( qgsDoubleNear( vLength.toDouble(), 26932.156, 0.001 ) );
QgsExpression expLength2( "$length" );
expLength2.setGeomCalculator( da );
vLength = expLength2.evaluate( &context );
expected = 26932.156;
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
// test unit conversion
expLength2.setDistanceUnits( QGis::Meters ); //default units should be meters
vLength = expLength2.evaluate( &context );
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
expLength2.setDistanceUnits( QGis::UnknownUnit ); //unknown units should not be converted
vLength = expLength2.evaluate( &context );
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
expLength2.setDistanceUnits( QGis::Feet );
expected = 88360.0918635;
vLength = expLength2.evaluate( &context );
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
}

void eval_geometry_wkt()
Expand Down

0 comments on commit 9f772bc

Please sign in to comment.