Skip to content

Commit

Permalink
Respect project ellipsoid and unit settings in virtual fields
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Feb 16, 2016
1 parent 2265eb9 commit 4094bae
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 1 deletion.
13 changes: 13 additions & 0 deletions src/core/qgsvectorlayerfeatureiterator.cpp
Expand Up @@ -23,13 +23,17 @@
#include "qgsvectorlayer.h"
#include "qgsvectorlayerjoinbuffer.h"
#include "qgsexpressioncontext.h"
#include "qgsdistancearea.h"
#include "qgsproject.h"

QgsVectorLayerFeatureSource::QgsVectorLayerFeatureSource( QgsVectorLayer *layer )
: mCrsId( 0 )
{
mProviderFeatureSource = layer->dataProvider()->featureSource();
mFields = layer->fields();
mJoinBuffer = layer->mJoinBuffer->clone();
mExpressionFieldBuffer = new QgsExpressionFieldBuffer( *layer->mExpressionFieldBuffer );
mCrsId = layer->crs().srsid();

mCanBeSimplified = layer->hasGeometryType() && layer->geometryType() != QGis::Point;

Expand Down Expand Up @@ -544,6 +548,15 @@ void QgsVectorLayerFeatureIterator::prepareExpressions()
{
int oi = mSource->mFields.fieldOriginIndex( i );
QgsExpression* exp = new QgsExpression( exps[oi].cachedExpression );

QgsDistanceArea da;
da.setSourceCrs( mSource->mCrsId );
da.setEllipsoidalMode( true );
da.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
exp->setGeomCalculator( da );
exp->setDistanceUnits( QgsProject::instance()->distanceUnits() );
exp->setAreaUnits( QgsProject::instance()->areaUnits() );

exp->prepare( mExpressionContext.data() );
mExpressionFieldInfo.insert( i, exp );

Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsvectorlayerfeatureiterator.h
Expand Up @@ -66,6 +66,8 @@ class QgsVectorLayerFeatureSource : public QgsAbstractFeatureSource
QList<QgsField> mAddedAttributes;
QgsChangedAttributesMap mChangedAttributeValues;
QgsAttributeList mDeletedAttributeIds;

long mCrsId;
};


Expand Down
65 changes: 64 additions & 1 deletion tests/src/python/test_qgsvectorlayer.py
Expand Up @@ -29,7 +29,10 @@
QgsMapLayerRegistry,
QgsVectorJoinInfo,
QgsSymbolV2,
QgsSingleSymbolRendererV2)
QgsSingleSymbolRendererV2,
QgsCoordinateReferenceSystem,
QgsProject,
QgsUnitTypes)
from qgis.testing import (start_app,
unittest
)
Expand Down Expand Up @@ -975,6 +978,66 @@ def test_ExpressionField(self):

self.assertEquals(layer.pendingFields().count(), cnt)

def test_ExpressionFieldEllipsoidLengthCalculation(self):
#create a temporary layer
temp_layer = QgsVectorLayer("LineString?crs=epsg:3111&field=pk:int", "vl", "memory")
assert temp_layer.isValid()
f1 = QgsFeature(temp_layer.dataProvider().fields(), 1)
f1.setAttribute("pk", 1)
f1.setGeometry(QgsGeometry.fromPolyline([QgsPoint(2484588, 2425722), QgsPoint(2482767, 2398853)]))
temp_layer.dataProvider().addFeatures([f1])

# set project CRS and ellipsoid
srs = QgsCoordinateReferenceSystem(3111, QgsCoordinateReferenceSystem.EpsgCrsId)
QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCRSProj4String", srs.toProj4())
QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCRSID", srs.srsid())
QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCrs", srs.authid())
QgsProject.instance().writeEntry("Measure", "/Ellipsoid", "WGS84")
QgsProject.instance().writeEntry("Measurement", "/DistanceUnits", QgsUnitTypes.encodeUnit(QGis.Meters))

idx = temp_layer.addExpressionField('$length', QgsField('length', QVariant.Double))

# check value
f = temp_layer.getFeatures().next()
expected = 26932.156
self.assertAlmostEqual(f['length'], expected, 3)

# change project length unit, check calculation respects unit
QgsProject.instance().writeEntry("Measurement", "/DistanceUnits", QgsUnitTypes.encodeUnit(QGis.Feet))
f = temp_layer.getFeatures().next()
expected = 88360.0918635
self.assertAlmostEqual(f['length'], expected, 3)

def test_ExpressionFieldEllipsoidAreaCalculation(self):
#create a temporary layer
temp_layer = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory")
assert temp_layer.isValid()
f1 = QgsFeature(temp_layer.dataProvider().fields(), 1)
f1.setAttribute("pk", 1)
f1.setGeometry(QgsGeometry.fromPolygon([[QgsPoint(2484588, 2425722), QgsPoint(2482767, 2398853), QgsPoint(2520109, 2397715), QgsPoint(2520792, 2425494), QgsPoint(2484588, 2425722)]]))
temp_layer.dataProvider().addFeatures([f1])

# set project CRS and ellipsoid
srs = QgsCoordinateReferenceSystem(3111, QgsCoordinateReferenceSystem.EpsgCrsId)
QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCRSProj4String", srs.toProj4())
QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCRSID", srs.srsid())
QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCrs", srs.authid())
QgsProject.instance().writeEntry("Measure", "/Ellipsoid", "WGS84")
QgsProject.instance().writeEntry("Measurement", "/AreaUnits", QgsUnitTypes.encodeUnit(QgsUnitTypes.SquareMeters))

idx = temp_layer.addExpressionField('$area', QgsField('area', QVariant.Double))

# check value
f = temp_layer.getFeatures().next()
expected = 1009089817.0
self.assertAlmostEqual(f['area'], expected, 0)

# change project area unit, check calculation respects unit
QgsProject.instance().writeEntry("Measurement", "/AreaUnits", QgsUnitTypes.encodeUnit(QgsUnitTypes.SquareMiles))
f = temp_layer.getFeatures().next()
expected = 389.6117565069
self.assertAlmostEqual(f['area'], expected, 3)

def test_ExpressionFilter(self):
layer = createLayerWithOnePoint()

Expand Down

0 comments on commit 4094bae

Please sign in to comment.