Skip to content

Commit 1f23ba9

Browse files
author
homann
committed
Backport for measuring from trunk to 0.8. Not everything is ported, but the main functionality should at least be correct.
git-svn-id: http://svn.osgeo.org/qgis/branches/Release-0_8_0@6818 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 185a7fc commit 1f23ba9

File tree

3 files changed

+292
-95
lines changed

3 files changed

+292
-95
lines changed

src/core/qgsdistancearea.cpp

Lines changed: 223 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,34 @@
1717
#include <cmath>
1818
#include <sqlite3.h>
1919
#include <QDir>
20-
#include <QSettings>
20+
#include <QString>
21+
#include <QLocale>
22+
#include <QObject>
2123

2224
#include "qgis.h"
2325
#include "qgspoint.h"
24-
#include "qgsproject.h"
2526
#include "qgscoordinatetransform.h"
2627
#include "qgsspatialrefsys.h"
2728
#include "qgsgeometry.h"
2829
#include "qgsdistancearea.h"
2930
#include "qgsapplication.h"
3031
#include "qgslogger.h"
3132

33+
// MSVC compiler doesn't have defined M_PI in math.h
34+
#ifndef M_PI
35+
#define M_PI 3.14159265358979323846
36+
#endif
37+
3238
#define DEG2RAD(x) ((x)*M_PI/180)
3339

3440

3541
QgsDistanceArea::QgsDistanceArea()
3642
{
3743
// init with default settings
44+
mProjectionsEnabled = FALSE;
3845
mCoordTransform = new QgsCoordinateTransform;
39-
setDefaultEllipsoid();
40-
setProjectAsSourceSRS();
46+
setSourceSRS(GEOSRS_ID); // WGS 84
47+
setEllipsoid("WGS84");
4148
}
4249

4350

@@ -47,27 +54,17 @@ QgsDistanceArea::~QgsDistanceArea()
4754
}
4855

4956

50-
void QgsDistanceArea::setSourceSRS(long srsid)
57+
void QgsDistanceArea::setProjectionsEnabled(bool flag)
5158
{
52-
QgsSpatialRefSys srcSRS;
53-
srcSRS.createFromSrsId(srsid);
54-
mCoordTransform->setSourceSRS(srcSRS);
59+
mProjectionsEnabled = flag;
5560
}
5661

5762

58-
void QgsDistanceArea::setProjectAsSourceSRS()
63+
void QgsDistanceArea::setSourceSRS(long srsid)
5964
{
60-
// This function used to only get the /ProjectSRSID if on-the-fly
61-
// projection was enabled (and used a default value in all other
62-
// cases). However, even if it was not, a valid value for
63-
// /ProjectSRSID is most likely available, and we now use it in all
64-
// cases (as it gives correct distances and areas even when
65-
// on-the-fly projection is turned off). The default of GEOSRS_ID
66-
// is still applied if all else fails.
67-
68-
int srsid = QgsProject::instance()->readNumEntry("SpatialRefSys","/ProjectSRSID",GEOSRS_ID);
69-
70-
setSourceSRS(srsid);
65+
QgsSpatialRefSys srcSRS;
66+
srcSRS.createFromSrsId(srsid);
67+
mCoordTransform->setSourceSRS(srcSRS);
7168
}
7269

7370

@@ -81,6 +78,14 @@ bool QgsDistanceArea::setEllipsoid(const QString& ellipsoid)
8178
const char *myTail;
8279
sqlite3_stmt *myPreparedStatement;
8380
int myResult;
81+
82+
// Shortcut if ellipsoid is none.
83+
if (ellipsoid == "NONE")
84+
{
85+
mEllipsoid = "NONE";
86+
return true;
87+
}
88+
8489
//check the db is available
8590
myResult = sqlite3_open(QString(QgsApplication::qgisUserDbFilePath()).latin1(), &myDatabase);
8691
if(myResult)
@@ -170,26 +175,6 @@ bool QgsDistanceArea::setEllipsoid(const QString& ellipsoid)
170175
}
171176

172177

173-
bool QgsDistanceArea::setDefaultEllipsoid()
174-
{
175-
QString defEll("WGS84");
176-
QString ellKey("/qgis/measure/ellipsoid");
177-
QSettings settings;
178-
QString ellipsoid = settings.readEntry(ellKey, defEll);
179-
180-
// Somehow/sometimes the settings file can have a blank ellipsoid
181-
// value. This is undesirable, so force a valid default value in
182-
// that case, and fix the problem by writing a valid value.
183-
if (ellipsoid.isEmpty())
184-
{
185-
ellipsoid = defEll;
186-
settings.writeEntry(ellKey, ellipsoid);
187-
}
188-
189-
return setEllipsoid(ellipsoid);
190-
}
191-
192-
193178
double QgsDistanceArea::measure(QgsGeometry* geometry)
194179
{
195180
unsigned char* wkb = geometry->wkbBuffer();
@@ -246,6 +231,7 @@ unsigned char* QgsDistanceArea::measureLine(unsigned char* feature, double* area
246231

247232
std::vector<QgsPoint> points(nPoints);
248233

234+
QgsDebugMsg("This feature WKB has " + QString::number(nPoints) + " points");
249235
// Extract the points from the WKB format into the vector
250236
for (unsigned int i = 0; i < nPoints; ++i)
251237
{
@@ -265,18 +251,32 @@ double QgsDistanceArea::measureLine(const std::vector<QgsPoint>& points)
265251
if (points.size() < 2)
266252
return 0;
267253

254+
double total = 0;
255+
QgsPoint p1, p2;
256+
268257
try
269258
{
270-
double total = 0;
271-
QgsPoint p1, p2;
272-
p1 = mCoordTransform->transform(points[0]);
273-
274-
for (int i = 1; i < points.size(); i++)
259+
if (mProjectionsEnabled && (mEllipsoid != "NONE"))
260+
p1 = mCoordTransform->transform(points[0]);
261+
else
262+
p1 = points[0];
263+
264+
for (std::vector<QgsPoint>::size_type i = 1; i < points.size(); i++)
275265
{
276-
p2 = mCoordTransform->transform(points[i]);
277-
total = computeDistanceBearing(p1,p2);
266+
if (mProjectionsEnabled && (mEllipsoid != "NONE"))
267+
{
268+
p2 = mCoordTransform->transform(points[i]);
269+
total += computeDistanceBearing(p1,p2);
270+
}
271+
else
272+
{
273+
p2 = points[i];
274+
total += measureLine(p1,p2);
275+
}
276+
278277
p1 = p2;
279278
}
279+
280280
return total;
281281
}
282282
catch (QgsCsException &cse)
@@ -291,9 +291,17 @@ double QgsDistanceArea::measureLine(const QgsPoint& p1, const QgsPoint& p2)
291291
{
292292
try
293293
{
294-
QgsPoint pp1 = mCoordTransform->transform(p1);
295-
QgsPoint pp2 = mCoordTransform->transform(p2);
296-
return computeDistanceBearing(pp1, pp2);
294+
QgsPoint pp1 = p1, pp2 = p2;
295+
if (mProjectionsEnabled && (mEllipsoid != "NONE"))
296+
{
297+
pp1 = mCoordTransform->transform(p1);
298+
pp2 = mCoordTransform->transform(p2);
299+
return computeDistanceBearing(pp1, pp2);
300+
}
301+
else
302+
{
303+
return sqrt((p2.x()-p1.x())*(p2.x()-p1.x()) + (p2.y()-p1.y())*(p2.y()-p1.y()));
304+
}
297305
}
298306
catch (QgsCsException &cse)
299307
{
@@ -328,14 +336,18 @@ unsigned char* QgsDistanceArea::measurePolygon(unsigned char* feature, double* a
328336

329337
// Extract the points from the WKB and store in a pair of
330338
// vectors.
331-
for (unsigned int jdx = 0; jdx < nPoints; jdx++)
339+
for (int jdx = 0; jdx < nPoints; jdx++)
332340
{
333341
x = *((double *) ptr);
334342
ptr += sizeof(double);
335343
y = *((double *) ptr);
336344
ptr += sizeof(double);
337345

338-
points[jdx] = mCoordTransform->transform(QgsPoint(x,y));
346+
points[jdx] = QgsPoint(x,y);
347+
if (mProjectionsEnabled && (mEllipsoid != "NONE"))
348+
{
349+
points[jdx] = mCoordTransform->transform(points[jdx]);
350+
}
339351
}
340352

341353
if (points.size() > 2)
@@ -359,14 +371,22 @@ unsigned char* QgsDistanceArea::measurePolygon(unsigned char* feature, double* a
359371

360372
double QgsDistanceArea::measurePolygon(const std::vector<QgsPoint>& points)
361373
{
374+
362375
try
363376
{
364-
std::vector<QgsPoint> pts(points.size());
365-
for (std::vector<QgsPoint>::size_type i = 0; i < points.size(); i++)
377+
if (mProjectionsEnabled && (mEllipsoid != "NONE"))
366378
{
367-
pts[i] = mCoordTransform->transform(points[i]);
379+
std::vector<QgsPoint> pts(points.size());
380+
for (std::vector<QgsPoint>::size_type i = 0; i < points.size(); i++)
381+
{
382+
pts[i] = mCoordTransform->transform(points[i]);
383+
}
384+
return computePolygonArea(pts);
385+
}
386+
else
387+
{
388+
return computePolygonArea(points);
368389
}
369-
return computePolygonArea(pts);
370390
}
371391
catch (QgsCsException &cse)
372392
{
@@ -376,6 +396,20 @@ double QgsDistanceArea::measurePolygon(const std::vector<QgsPoint>& points)
376396
}
377397

378398

399+
double QgsDistanceArea::getBearing(const QgsPoint& p1, const QgsPoint& p2)
400+
{
401+
QgsPoint pp1 = p1, pp2 = p2;
402+
if (mProjectionsEnabled && (mEllipsoid != "NONE"))
403+
{
404+
pp1 = mCoordTransform->transform(p1);
405+
pp2 = mCoordTransform->transform(p2);
406+
}
407+
408+
double bearing;
409+
computeDistanceBearing(pp1, pp2, &bearing);
410+
return bearing;
411+
}
412+
379413

380414
///////////////////////////////////////////////////////////
381415
// distance calculation
@@ -512,6 +546,11 @@ double QgsDistanceArea::computePolygonArea(const std::vector<QgsPoint>& points)
512546
double Qbar1, Qbar2;
513547
double area;
514548

549+
QgsDebugMsg("Ellipsoid: " + mEllipsoid);
550+
if ((! mProjectionsEnabled) || (mEllipsoid == "NONE"))
551+
{
552+
return computePolygonFlatArea(points);
553+
}
515554
int n = points.size();
516555
x2 = DEG2RAD(points[n-1].x());
517556
y2 = DEG2RAD(points[n-1].y());
@@ -556,3 +595,131 @@ double QgsDistanceArea::computePolygonArea(const std::vector<QgsPoint>& points)
556595
return area;
557596
}
558597

598+
double QgsDistanceArea::computePolygonFlatArea(const std::vector<QgsPoint>& points)
599+
{
600+
// Normal plane area calculations.
601+
double area = 0.0;
602+
int i, size;
603+
604+
size = points.size();
605+
606+
// QgsDebugMsg("New area calc, nr of points: " + QString::number(size));
607+
for(i = 0; i < size; i++)
608+
{
609+
// QgsDebugMsg("Area from point: " + (points[i]).stringRep(2));
610+
// Using '% size', so that we always end with the starting point
611+
// and thus close the polygon.
612+
area = area + points[i].x()*points[(i+1) % size].y() - points[(i+1) % size].x()*points[i].y();
613+
}
614+
// QgsDebugMsg("Area from point: " + (points[i % size]).stringRep(2));
615+
area = area / 2.0;
616+
return fabs(area); // All areas are positive!
617+
}
618+
619+
QString QgsDistanceArea::textUnit(double value, int decimals, QGis::units u, bool isArea)
620+
{
621+
QString unitLabel;
622+
623+
624+
switch (u)
625+
{
626+
case QGis::METERS:
627+
if (isArea)
628+
{
629+
if (fabs(value) > 1000000.0)
630+
{
631+
unitLabel = QObject::tr(" km2");
632+
value = value / 1000000.0;
633+
}
634+
else if (fabs(value) > 1000.0)
635+
{
636+
unitLabel = QObject::tr(" ha");
637+
value = value / 10000.0;
638+
}
639+
else
640+
{
641+
unitLabel = QObject::tr(" m2");
642+
}
643+
}
644+
else
645+
{
646+
if (fabs(value) == 0.0)
647+
{
648+
// Special case for pretty printing.
649+
unitLabel=QObject::tr(" m");
650+
651+
}
652+
else if (fabs(value) > 1000.0)
653+
{
654+
unitLabel=QObject::tr(" km");
655+
value = value/1000;
656+
}
657+
else if (fabs(value) < 0.01)
658+
{
659+
unitLabel=QObject::tr(" mm");
660+
value = value*1000;
661+
}
662+
else if (fabs(value) < 0.1)
663+
{
664+
unitLabel=QObject::tr(" cm");
665+
value = value*100;
666+
}
667+
else
668+
{
669+
unitLabel=QObject::tr(" m");
670+
}
671+
}
672+
break;
673+
case QGis::FEET:
674+
if (isArea)
675+
{
676+
if (fabs(value) > (528.0*528.0))
677+
{
678+
unitLabel = QObject::tr(" sq mile");
679+
value = value / (5280.0*5280.0);
680+
}
681+
else
682+
{
683+
unitLabel = QObject::tr(" sq ft");
684+
}
685+
}
686+
else
687+
{
688+
if (fabs(value) > 528.0)
689+
{
690+
unitLabel = QObject::tr(" mile");
691+
value = value / 5280.0;
692+
}
693+
else
694+
{
695+
if (fabs(value) == 1.0)
696+
unitLabel=QObject::tr(" foot");
697+
else
698+
unitLabel=QObject::tr(" feet");
699+
}
700+
}
701+
break;
702+
case QGis::DEGREES:
703+
if (isArea)
704+
{
705+
unitLabel = QObject::tr(" sq.deg.");
706+
}
707+
else
708+
{
709+
if (fabs(value) == 1.0)
710+
unitLabel=QObject::tr(" degree");
711+
else
712+
unitLabel=QObject::tr(" degrees");
713+
}
714+
break;
715+
case QGis::UNKNOWN:
716+
unitLabel=QObject::tr(" unknown");
717+
default:
718+
std::cout << "Error: not picked up map units - actual value = "
719+
<< u << std::endl;
720+
};
721+
722+
723+
return QLocale::system().toString(value, 'f', decimals) + unitLabel;
724+
725+
}

0 commit comments

Comments
 (0)