Skip to content

Commit 9f772bc

Browse files
committedFeb 13, 2016
Add API call for setting preferred distance unit for QgsExpression
(refs #13209, #12939, #4857)
1 parent 99e52af commit 9f772bc

File tree

5 files changed

+99
-10
lines changed

5 files changed

+99
-10
lines changed
 

‎python/core/qgsexpression.sip

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class QgsExpression
139139
/** Return calculator used for distance and area calculations
140140
* (used by $length, $area and $perimeter functions only)
141141
* @see setGeomCalculator()
142+
* @see distanceUnits()
142143
*/
143144
QgsDistanceArea *geomCalculator();
144145

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

154+
/** Returns the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perimeter".
155+
* @note distances are only converted when a geomCalculator() has been set
156+
* @note added in QGIS 2.14
157+
* @see setDistanceUnits()
158+
*/
159+
QGis::UnitType distanceUnits() const;
160+
161+
/** Sets the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perimeter".
162+
* @note distances are only converted when a geomCalculator() has been set
163+
* @note added in QGIS 2.14
164+
* @see distanceUnits()
165+
*/
166+
void setDistanceUnits( QGis::UnitType unit );
167+
153168
/** This function currently replaces each expression between [% and %]
154169
in the string with the result of its evaluation on the feature
155170
passed as argument.

‎src/core/qgsexpression.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,7 +1685,9 @@ static QVariant fcnGeomLength( const QVariantList&, const QgsExpressionContext*
16851685
QgsDistanceArea* calc = parent->geomCalculator();
16861686
if ( calc )
16871687
{
1688-
return QVariant( calc->measureLength( f.constGeometry() ) );
1688+
double len = calc->measureLength( f.constGeometry() );
1689+
len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
1690+
return QVariant( len );
16891691
}
16901692
else
16911693
{
@@ -1700,7 +1702,9 @@ static QVariant fcnGeomPerimeter( const QVariantList&, const QgsExpressionContex
17001702
QgsDistanceArea* calc = parent->geomCalculator();
17011703
if ( calc )
17021704
{
1703-
return QVariant( calc->measurePerimeter( f.constGeometry() ) );
1705+
double len = calc->measurePerimeter( f.constGeometry() );
1706+
len = calc->convertLengthMeasurement( len, parent->distanceUnits() );
1707+
return QVariant( len );
17041708
}
17051709
else
17061710
{
@@ -3411,6 +3415,16 @@ QgsDistanceArea* QgsExpression::geomCalculator()
34113415
return d->mCalc.data();
34123416
}
34133417

3418+
QGis::UnitType QgsExpression::distanceUnits() const
3419+
{
3420+
return d->mDistanceUnit;
3421+
}
3422+
3423+
void QgsExpression::setDistanceUnits( QGis::UnitType unit )
3424+
{
3425+
d->mDistanceUnit = unit;
3426+
}
3427+
34143428
void QgsExpression::acceptVisitor( QgsExpression::Visitor& v ) const
34153429
{
34163430
if ( d->mRootNode )

‎src/core/qgsexpression.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ class CORE_EXPORT QgsExpression
278278
/** Return calculator used for distance and area calculations
279279
* (used by $length, $area and $perimeter functions only)
280280
* @see setGeomCalculator()
281+
* @see distanceUnits()
281282
*/
282283
QgsDistanceArea* geomCalculator();
283284

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

294+
/** Returns the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perimeter".
295+
* @note distances are only converted when a geomCalculator() has been set
296+
* @note added in QGIS 2.14
297+
* @see setDistanceUnits()
298+
*/
299+
QGis::UnitType distanceUnits() const;
300+
301+
/** Sets the desired distance units for calculations involving geomCalculator(), eg "$length" and "$perimeter".
302+
* @note distances are only converted when a geomCalculator() has been set
303+
* @note added in QGIS 2.14
304+
* @see distanceUnits()
305+
*/
306+
void setDistanceUnits( QGis::UnitType unit );
307+
293308
/** This function currently replaces each expression between [% and %]
294309
in the string with the result of its evaluation on the feature
295310
passed as argument.

‎src/core/qgsexpressionprivate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class QgsExpressionPrivate
3838
, mRowNumber( 0 )
3939
, mScale( 0 )
4040
, mCalc( nullptr )
41+
, mDistanceUnit( QGis::UnknownUnit )
4142
{}
4243

4344
QgsExpressionPrivate( const QgsExpressionPrivate& other )
@@ -48,6 +49,7 @@ class QgsExpressionPrivate
4849
, mScale( other.mScale )
4950
, mExp( other.mExp )
5051
, mCalc( other.mCalc )
52+
, mDistanceUnit( other.mDistanceUnit )
5153
{}
5254

5355
~QgsExpressionPrivate()
@@ -67,6 +69,7 @@ class QgsExpressionPrivate
6769
QString mExp;
6870

6971
QSharedPointer<QgsDistanceArea> mCalc;
72+
QGis::UnitType mDistanceUnit;
7073
};
7174
///@endcond
7275

‎tests/src/core/testqgsexpression.cpp

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,12 +1327,33 @@ class TestQgsExpression: public QObject
13271327
// test perimeter without geomCalculator
13281328
QgsExpression expPerimeter( "$perimeter" );
13291329
QVariant vPerimeter = expPerimeter.evaluate( &context );
1330-
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), 128282.086, 0.001 ) );
1330+
double expected = 128282.086;
1331+
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
1332+
// units should not be converted if no geometry calculator set
1333+
expPerimeter.setDistanceUnits( QGis::Feet );
1334+
vPerimeter = expPerimeter.evaluate( &context );
1335+
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
1336+
expPerimeter.setDistanceUnits( QGis::NauticalMiles );
1337+
vPerimeter = expPerimeter.evaluate( &context );
1338+
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
13311339

13321340
// test perimeter with geomCalculator
1333-
expPerimeter.setGeomCalculator( da );
1334-
vPerimeter = expPerimeter.evaluate( &context );
1335-
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), 128289.074, 0.001 ) );
1341+
QgsExpression expPerimeter2( "$perimeter" );
1342+
expPerimeter2.setGeomCalculator( da );
1343+
vPerimeter = expPerimeter2.evaluate( &context );
1344+
expected = 128289.074;
1345+
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
1346+
// test unit conversion
1347+
expPerimeter2.setDistanceUnits( QGis::Meters ); //default units should be meters
1348+
vPerimeter = expPerimeter2.evaluate( &context );
1349+
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
1350+
expPerimeter2.setDistanceUnits( QGis::UnknownUnit ); //unknown units should not be converted
1351+
vPerimeter = expPerimeter2.evaluate( &context );
1352+
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
1353+
expPerimeter2.setDistanceUnits( QGis::Feet );
1354+
expected = 420895.9120735;
1355+
vPerimeter = expPerimeter2.evaluate( &context );
1356+
QVERIFY( qgsDoubleNear( vPerimeter.toDouble(), expected, 0.001 ) );
13361357

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

13431364
QgsExpression expLength( "$length" );
13441365
QVariant vLength = expLength.evaluate( &context );
1345-
QVERIFY( qgsDoubleNear( vLength.toDouble(), 26930.637, 0.001 ) );
1366+
expected = 26930.637;
1367+
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
1368+
// units should not be converted if no geometry calculator set
1369+
expLength.setDistanceUnits( QGis::Feet );
1370+
vLength = expLength.evaluate( &context );
1371+
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
1372+
expLength.setDistanceUnits( QGis::NauticalMiles );
1373+
vLength = expLength.evaluate( &context );
1374+
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
13461375

13471376
// test length with geomCalculator
1348-
expLength.setGeomCalculator( da );
1349-
vLength = expLength.evaluate( &context );
1350-
QVERIFY( qgsDoubleNear( vLength.toDouble(), 26932.156, 0.001 ) );
1377+
QgsExpression expLength2( "$length" );
1378+
expLength2.setGeomCalculator( da );
1379+
vLength = expLength2.evaluate( &context );
1380+
expected = 26932.156;
1381+
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
1382+
// test unit conversion
1383+
expLength2.setDistanceUnits( QGis::Meters ); //default units should be meters
1384+
vLength = expLength2.evaluate( &context );
1385+
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
1386+
expLength2.setDistanceUnits( QGis::UnknownUnit ); //unknown units should not be converted
1387+
vLength = expLength2.evaluate( &context );
1388+
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
1389+
expLength2.setDistanceUnits( QGis::Feet );
1390+
expected = 88360.0918635;
1391+
vLength = expLength2.evaluate( &context );
1392+
QVERIFY( qgsDoubleNear( vLength.toDouble(), expected, 0.001 ) );
13511393
}
13521394

13531395
void eval_geometry_wkt()

0 commit comments

Comments
 (0)
Please sign in to comment.