Skip to content

Commit

Permalink
Merge pull request #4104 from nyalldawson/area
Browse files Browse the repository at this point in the history
Forward port curvepolygon area fixes to 2.18
  • Loading branch information
nyalldawson committed Feb 4, 2017
2 parents 73e0811 + c0516a4 commit 4bcb1dd
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 19 deletions.
3 changes: 1 addition & 2 deletions python/core/geometry/qgscurvev2.sip
Expand Up @@ -54,8 +54,7 @@ class QgsCurveV2: public QgsAbstractGeometryV2
*/
virtual int numPoints() const = 0;

/** Calculates the area of the curve. Derived classes should override this
* to return the correct area of the curve.
/** Sums up the area of the curve by iterating over the vertices (shoelace formula).
*/
virtual void sumUpArea( double& sum ) const = 0;

Expand Down
4 changes: 2 additions & 2 deletions src/core/geometry/qgscurvepolygonv2.cpp
Expand Up @@ -371,7 +371,7 @@ double QgsCurvePolygonV2::area() const

double totalArea = 0.0;

if ( mExteriorRing->isClosed() )
if ( mExteriorRing->isRing() )
{
double area = 0.0;
mExteriorRing->sumUpArea( area );
Expand All @@ -382,7 +382,7 @@ double QgsCurvePolygonV2::area() const
for ( ; ringIt != mInteriorRings.constEnd(); ++ringIt )
{
double area = 0.0;
if (( *ringIt )->isClosed() )
if (( *ringIt )->isRing() )
{
( *ringIt )->sumUpArea( area );
totalArea -= qAbs( area );
Expand Down
3 changes: 1 addition & 2 deletions src/core/geometry/qgscurvev2.h
Expand Up @@ -81,8 +81,7 @@ class CORE_EXPORT QgsCurveV2: public QgsAbstractGeometryV2
*/
virtual int numPoints() const = 0;

/** Calculates the area of the curve. Derived classes should override this
* to return the correct area of the curve.
/** Sums up the area of the curve by iterating over the vertices (shoelace formula).
*/
virtual void sumUpArea( double& sum ) const = 0;

Expand Down
3 changes: 0 additions & 3 deletions src/core/geometry/qgslinestringv2.cpp
Expand Up @@ -840,9 +840,6 @@ QgsPointV2 QgsLineStringV2::centroid() const
void QgsLineStringV2::sumUpArea( double& sum ) const
{
int maxIndex = numPoints() - 1;
if ( maxIndex == 1 )
return; //no area, just a single line

for ( int i = 0; i < maxIndex; ++i )
{
sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
Expand Down
33 changes: 30 additions & 3 deletions tests/src/core/testqgsgeometry.cpp
Expand Up @@ -27,6 +27,7 @@

//qgis includes...
#include <qgsapplication.h>
#include "qgscompoundcurvev2.h"
#include <qgsgeometry.h>
#include "qgsgeometryutils.h"
#include <qgspoint.h>
Expand Down Expand Up @@ -67,6 +68,7 @@ class TestQgsGeometry : public QObject
// geometry types
void pointV2(); //test QgsPointV2
void lineStringV2(); //test QgsLineStringV2
void compoundCurveV2(); //test QgsCompoundCurveV2
void polygonV2(); //test QgsPolygonV2
void multiPoint();
void multiLineString();
Expand Down Expand Up @@ -2077,13 +2079,13 @@ void TestQgsGeometry::lineStringV2()
QCOMPARE( area, 1.0 );
l36.setPoints( QgsPointSequenceV2() << QgsPointV2( 5, 10 ) << QgsPointV2( 10, 10 ) );
l36.sumUpArea( area );
QCOMPARE( area, 1.0 );
QVERIFY( qgsDoubleNear( area, -24 ) );
l36.setPoints( QgsPointSequenceV2() << QgsPointV2( 0, 0 ) << QgsPointV2( 2, 0 ) << QgsPointV2( 2, 2 ) );
l36.sumUpArea( area );
QVERIFY( qgsDoubleNear( area, 3.0 ) );
QVERIFY( qgsDoubleNear( area, -22 ) );
l36.setPoints( QgsPointSequenceV2() << QgsPointV2( 0, 0 ) << QgsPointV2( 2, 0 ) << QgsPointV2( 2, 2 ) << QgsPointV2( 0, 2 ) );
l36.sumUpArea( area );
QVERIFY( qgsDoubleNear( area, 7.0 ) );
QVERIFY( qgsDoubleNear( area, -18 ) );

//boundingBox - test that bounding box is updated after every modification to the line string
QgsLineStringV2 l37;
Expand Down Expand Up @@ -2200,6 +2202,31 @@ void TestQgsGeometry::lineStringV2()
QCOMPARE( static_cast< QgsPointV2*>( mpBoundary->geometryN( 1 ) )->z(), 20.0 );
}

void TestQgsGeometry::compoundCurveV2()
{
//test that area of a compound curve ring is equal to a closed linestring with the same vertices
QgsCompoundCurveV2 cc;
QgsLineStringV2* l1 = new QgsLineStringV2();
l1->setPoints( QgsPointSequenceV2() << QgsPointV2( 1, 1 ) << QgsPointV2( 0, 2 ) );
cc.addCurve( l1 );
QgsLineStringV2* l2 = new QgsLineStringV2();
l2->setPoints( QgsPointSequenceV2() << QgsPointV2( 0, 2 ) << QgsPointV2( -1, 0 ) << QgsPointV2( 0, -1 ) );
cc.addCurve( l2 );
QgsLineStringV2* l3 = new QgsLineStringV2();
l3->setPoints( QgsPointSequenceV2() << QgsPointV2( 0, -1 ) << QgsPointV2( 1, 1 ) );
cc.addCurve( l3 );

double ccArea = 0.0;
cc.sumUpArea( ccArea );

QgsLineStringV2 ls;
ls.setPoints( QgsPointSequenceV2() << QgsPointV2( 1, 1 ) << QgsPointV2( 0, 2 ) << QgsPointV2( -1, 0 ) << QgsPointV2( 0, -1 )
<< QgsPointV2( 1, 1 ) );
double lsArea = 0.0;
ls.sumUpArea( lsArea );
QVERIFY( qgsDoubleNear( ccArea, lsArea ) );
}

void TestQgsGeometry::polygonV2()
{
//test constructor
Expand Down
14 changes: 7 additions & 7 deletions tests/src/python/test_qgsgeometry.py
Expand Up @@ -180,31 +180,31 @@ def testReferenceGeometry(self):
bbox = geom.geometry().boundingBox()
exp = float(row['x_min'])
result = bbox.xMinimum()
assert doubleNear(result, exp), "Min X {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
self.assertAlmostEqual(result, exp, 5, "Min X {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
exp = float(row['y_min'])
result = bbox.yMinimum()
assert doubleNear(result, exp), "Min Y {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
self.assertAlmostEqual(result, exp, 5, "Min Y {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
exp = float(row['x_max'])
result = bbox.xMaximum()
assert doubleNear(result, exp), "Max X {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
self.assertAlmostEqual(result, exp, 5, "Max X {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))
exp = float(row['y_max'])
result = bbox.yMaximum()
assert doubleNear(result, exp), "Max Y {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
self.assertAlmostEqual(result, exp, 5, "Max Y {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))

# test area calculation
exp = float(row['area'])
result = geom.geometry().area()
assert doubleNear(result, exp), "Area {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
self.assertAlmostEqual(result, exp, 5, "Area {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))

# test length calculation
exp = float(row['length'])
result = geom.geometry().length()
assert doubleNear(result, exp, 0.00001), "Length {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
self.assertAlmostEqual(result, exp, 5, "Length {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))

# test perimeter calculation
exp = float(row['perimeter'])
result = geom.geometry().perimeter()
assert doubleNear(result, exp, 0.00001), "Perimeter {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result)
self.assertAlmostEqual(result, exp, 5, "Perimeter {}: mismatch Expected:\n{}\nGot:\n{}\n".format(i + 1, exp, result))

def testIntersection(self):
myLine = QgsGeometry.fromPolyline([
Expand Down
1 change: 1 addition & 0 deletions tests/testdata/geom_data.csv
Expand Up @@ -120,3 +120,4 @@ Polygon,,,,,,,,,,,,,,Malformed WKT
"PolygonM ((0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1, 5 7 1, 5 5 1),(1 1 1,2 1 1, 2 2 1, 1 2 1, 1 1 1))","POLYGON M ((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1),(1 1 1,2 1 1,2 2 1,1 2 1,1 1 1))",15,0,95,52,1,2,0,POINT(4.99473684210526 4.99473684210526),0,0,10,10,
"PolygonZ ((0 0 1 , 10 0 1, 10 10 1, 0 10 1, 0 0 1))","POLYGON Z ((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1))",5,0,100,40,1,0,0,POINT(5 5),0,0,10,10,
"PolygonZ ((0 0 1, 10 0 1, 10 10 1, 0 10 1, 0 0 1),(5 5 1, 7 5 1, 7 7 1 , 5 7 1, 5 5 1))","POLYGON Z ((0 0 1,10 0 1,10 10 1,0 10 1,0 0 1),(5 5 1,7 5 1,7 7 1,5 7 1,5 5 1))",10,0,96,48,1,1,0,POINT(4.95833333333333 4.95833333333333),0,0,10,10,
"CurvePolygon (CompoundCurve ((2678124.57778842002153397 1225804.43286111624911427, 2678251.0684670670889318 1225964.66278979112394154, 2678201.75901959836483002 1226077.95337014575488865, 2678199.27904875669628382 1226083.94340024818666279, 2678198.13904719380661845 1226083.5034040967002511, 2678188.08903313148766756 1226079.56343783461488783, 2678164.688993189483881 1226068.85351158352568746, 2678152.65896565327420831 1226061.85354482522234321, 2678133.63892276119440794 1226050.92359781125560403),CircularString (2678133.63892276119440794 1226050.92359781125560403, 2678124.47892813989892602 1226045.71365369856357574, 2678115.92887723352760077 1226039.55364341707900167, 2678110.39902341179549694 1226025.70413719792850316, 2678113.52874504774808884 1226011.12356549175456166, 2678117.04747172351926565 1226004.70550769660621881, 2678121.17868330329656601 1225998.66349145700223744, 2678122.91810466628521681 1225991.71089569479227066, 2678120.73861891590058804 1225984.88345037144608796, 2678109.63862727722153068 1225981.37343537760898471, 2678097.99861149024218321 1225981.17354299034923315, 2678087.07146158767864108 1225984.57272616261616349, 2678076.13865283969789743 1225987.95366438734345138, 2678068.26173875294625759 1225987.17441278789192438, 2678060.82864314317703247 1225984.45372360944747925, 2678052.37183309439569712 1225977.24715672573074698, 2678045.5285750487819314 1225968.49374381266534328, 2678039.90821403311565518 1225957.94303491595201194, 2678035.46847799280658364 1225946.84372220188379288, 2678033.64745173417031765 1225940.12937669246457517, 2678032.40841578459367156 1225933.28369381325319409, 2678033.68931351415812969 1225925.84029478346928954, 2678036.55834634136408567 1225918.85362965753301978, 2678039.0693440935574472 1225913.78109931806102395, 2678040.70829536207020283 1225908.363577825948596),(2678040.70829536207020283 1225908.363577825948596, 2678124.57778842002153397 1225804.43286111624911427)))","CurvePolygon (CompoundCurve ((2678124.57778842002153397 1225804.43286111624911427, 2678251.0684670670889318 1225964.66278979112394154, 2678201.75901959836483002 1226077.95337014575488865, 2678199.27904875669628382 1226083.94340024818666279, 2678198.13904719380661845 1226083.5034040967002511, 2678188.08903313148766756 1226079.56343783461488783, 2678164.688993189483881 1226068.85351158352568746, 2678152.65896565327420831 1226061.85354482522234321, 2678133.63892276119440794 1226050.92359781125560403),CircularString (2678133.63892276119440794 1226050.92359781125560403, 2678124.47892813989892602 1226045.71365369856357574, 2678115.92887723352760077 1226039.55364341707900167, 2678110.39902341179549694 1226025.70413719792850316, 2678113.52874504774808884 1226011.12356549175456166, 2678117.04747172351926565 1226004.70550769660621881, 2678121.17868330329656601 1225998.66349145700223744, 2678122.91810466628521681 1225991.71089569479227066, 2678120.73861891590058804 1225984.88345037144608796, 2678109.63862727722153068 1225981.37343537760898471, 2678097.99861149024218321 1225981.17354299034923315, 2678087.07146158767864108 1225984.57272616261616349, 2678076.13865283969789743 1225987.95366438734345138, 2678068.26173875294625759 1225987.17441278789192438, 2678060.82864314317703247 1225984.45372360944747925, 2678052.37183309439569712 1225977.24715672573074698, 2678045.5285750487819314 1225968.49374381266534328, 2678039.90821403311565518 1225957.94303491595201194, 2678035.46847799280658364 1225946.84372220188379288, 2678033.64745173417031765 1225940.12937669246457517, 2678032.40841578459367156 1225933.28369381325319409, 2678033.68931351415812969 1225925.84029478346928954, 2678036.55834634136408567 1225918.85362965753301978, 2678039.0693440935574472 1225913.78109931806102395, 2678040.70829536207020283 1225908.363577825948596),(2678040.70829536207020283 1225908.363577825948596, 2678124.57778842002153397 1225804.43286111624911427)))",34,0,32087.8047511,770.542777805,1,1,0,Point (2678143.67776390677317977 1225948.36456208629533648),2678032.40842,1225804.43286112,2678251.06846707,1226083.94340025,

0 comments on commit 4bcb1dd

Please sign in to comment.