Skip to content

Commit 1f23ba9

Browse files
author
homann
committedMar 18, 2007
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+
}

‎src/core/qgsdistancearea.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ General purpose distance and area calculator
3232
(both cases transform the coordinates from source SRS to the ellipse coords)
3333
- returned values are in meters resp. square meters
3434
*/
35-
class QgsDistanceArea
35+
class CORE_EXPORT QgsDistanceArea
3636
{
3737

3838
public:
@@ -43,19 +43,23 @@ class QgsDistanceArea
4343
//! Destructor
4444
~QgsDistanceArea();
4545

46+
//! sets whether coordinates must be projected to ellipsoid before measuring
47+
void setProjectionsEnabled(bool flag);
48+
49+
//! returns projections enabled flag
50+
bool projectionsEnabled() { return mProjectionsEnabled; }
51+
4652
//! sets source spatial reference system (by QGIS SRS)
4753
void setSourceSRS(long srsid);
48-
//! sets project's SRS as source
49-
void setProjectAsSourceSRS();
54+
5055
//! returns source spatial reference system
5156
long sourceSRS() { return mSourceRefSys; }
5257
//! What sort of coordinate system is being used?
5358
bool geographic() { return mCoordTransform->sourceSRS().geographicFlag(); }
5459

5560
//! sets ellipsoid by its acronym
5661
bool setEllipsoid(const QString& ellipsoid);
57-
//! sets ellipsoid which has been specified in preferences
58-
bool setDefaultEllipsoid();
62+
5963
//! returns ellipsoid's acronym
6064
const QString& ellipsoid() { return mEllipsoid; }
6165

@@ -76,6 +80,11 @@ class QgsDistanceArea
7680

7781
//! measures polygon area
7882
double measurePolygon(const std::vector<QgsPoint>& points);
83+
84+
//! compute bearing - in radians
85+
double getBearing(const QgsPoint& p1, const QgsPoint& p2);
86+
87+
static QString textUnit(double value, int decimals, QGis::units u, bool isArea);
7988

8089
protected:
8190

@@ -104,6 +113,8 @@ class QgsDistanceArea
104113
105114
*/
106115
double computePolygonArea(const std::vector<QgsPoint>& points);
116+
117+
double computePolygonFlatArea(const std::vector<QgsPoint>& points);
107118

108119
/**
109120
precalculates some values
@@ -116,6 +127,9 @@ class QgsDistanceArea
116127
//! used for transforming coordinates from source SRS to ellipsoid's coordinates
117128
QgsCoordinateTransform* mCoordTransform;
118129

130+
//! indicates whether we will transform coordinates
131+
bool mProjectionsEnabled;
132+
119133
//! id of the source spatial reference system
120134
long mSourceRefSys;
121135

‎src/gui/qgsmeasure.cpp

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@
2020
#include "qgscontexthelp.h"
2121
#include "qgsdistancearea.h"
2222
#include "qgsmapcanvas.h"
23+
#include "qgsmaprender.h"
2324
#include "qgsmaptopixel.h"
2425
#include "qgsrubberband.h"
26+
#include "qgsspatialrefsys.h"
27+
#include "qgsproject.h"
2528

2629
#include "QMessageBox"
2730
#include <QSettings>
31+
#include <QLocale>
2832
#include <iostream>
2933

3034

@@ -50,7 +54,7 @@ QgsMeasure::QgsMeasure(bool measureArea, QgsMapCanvas *mc, Qt::WFlags f)
5054
mTable->setNumRows(1);
5155
mTable->setText(0, 0, QString::number(0, 'f',1));
5256

53-
mTable->horizontalHeader()->setLabel( 0, tr("Segments (in meters)") );
57+
//mTable->horizontalHeader()->setLabel( 0, tr("Segments (in meters)") );
5458
//mTable->horizontalHeader()->setLabel( 1, tr("Total") );
5559
//mTable->horizontalHeader()->setLabel( 2, tr("Azimuth") );
5660

@@ -94,9 +98,7 @@ void QgsMeasure::activate()
9498
"If so, the results from line or area measurements will be "
9599
"incorrect.</p>"
96100
"<p>To fix this, explicitly set an appropriate map coordinate "
97-
"system using the <tt>Settings:Project Properties</tt> menu."),
98-
QMessageBox::Ok,
99-
QMessageBox::NoButton);
101+
"system using the <tt>Settings:Project Properties</tt> menu."));
100102
mWrongProjectProjection = true;
101103
}
102104
}
@@ -177,12 +179,11 @@ void QgsMeasure::addPoint(QgsPoint &point)
177179
editTotal->setText(formatDistance(mTotal));
178180

179181

180-
int row = mPoints.size()-2;
181-
mTable->setText(row, 0, QString::number(d, 'f',1));
182-
//mTable->setText ( row, 1, QString::number(mTotal) );
182+
int row = mPoints.size()-2;
183+
mTable->setText(row, 0, QLocale::system().toString(d, 'f', 2));
183184
mTable->setNumRows ( mPoints.size() );
184185

185-
mTable->setText(row + 1, 0, QString::number(0, 'f',1));
186+
mTable->setText(row + 1, 0, QLocale::system().toString(0.0, 'f', 2));
186187
mTable->ensureCellVisible(row + 1,0);
187188
}
188189

@@ -225,7 +226,8 @@ void QgsMeasure::mouseMove(QgsPoint &point)
225226
QgsPoint p1 = tmpPoints[last], p2 = tmpPoints[last+1];
226227

227228
double d = mCalc->measureLine(p1,p2);
228-
mTable->setText(last, 0, QString::number(d, 'f',1));
229+
//mTable->setText(last, 0, QString::number(d, 'f',1));
230+
mTable->setText(last, 0, QLocale::system().toString(d, 'f', 2));
229231
editTotal->setText(formatDistance(mTotal + d));
230232
}
231233
}
@@ -289,37 +291,37 @@ void QgsMeasure::on_btnHelp_clicked()
289291
QString QgsMeasure::formatDistance(double distance)
290292
{
291293
QString txt;
292-
if (distance < 1000)
293-
{
294-
txt = QString::number(distance,'f',0);
295-
txt += " m";
296-
}
297-
else
298-
{
299-
txt = QString::number(distance/1000,'f',1);
300-
txt += " km";
301-
}
302-
return txt;
294+
QString unitLabel;
295+
296+
QGis::units myMapUnits = mCanvas->mapUnits();
297+
return QgsDistanceArea::textUnit(distance, 2, myMapUnits, false);
303298
}
304299

305300
QString QgsMeasure::formatArea(double area)
306301
{
307-
QString txt;
308-
if (area < 10000)
309-
{
310-
txt = QString::number(area,'f',0);
311-
txt += " m2";
312-
}
313-
else
314-
{
315-
txt = QString::number(area/1000000,'f',3);
316-
txt += " km2";
317-
}
318-
return txt;
302+
QGis::units myMapUnits = mCanvas->mapUnits();
303+
return QgsDistanceArea::textUnit(area, 2, myMapUnits, true);
319304
}
320305

321306
void QgsMeasure::updateUi()
322307
{
308+
309+
QGis::units myMapUnits = mCanvas->mapUnits();
310+
switch (myMapUnits)
311+
{
312+
case QGis::METERS:
313+
mTable->horizontalHeader()->setLabel( 0, tr("Segments (in meters)") );
314+
break;
315+
case QGis::FEET:
316+
mTable->horizontalHeader()->setLabel( 0, tr("Segments (in feet)") );
317+
break;
318+
case QGis::DEGREES:
319+
mTable->horizontalHeader()->setLabel( 0, tr("Segments (in degrees)") );
320+
break;
321+
case QGis::UNKNOWN:
322+
mTable->horizontalHeader()->setLabel( 0, tr("Segments") );
323+
};
324+
323325
if (mMeasureArea)
324326
{
325327
mTable->hide();
@@ -335,8 +337,22 @@ void QgsMeasure::updateUi()
335337

336338
void QgsMeasure::updateProjection()
337339
{
338-
mCalc->setDefaultEllipsoid();
339-
mCalc->setProjectAsSourceSRS();
340+
// set ellipsoid
341+
QSettings settings;
342+
QString ellipsoid = settings.readEntry("/qgis/measure/ellipsoid", "WGS84");
343+
mCalc->setEllipsoid(ellipsoid);
344+
345+
// set source SRS and projections enabled flag
346+
mCalc->setProjectionsEnabled(QgsProject::instance()->readNumEntry("SpatialRefSys","/ProjectionsEnabled",0));
347+
int srsid = QgsProject::instance()->readNumEntry("SpatialRefSys","/ProjectSRSID",GEOSRS_ID);
348+
349+
mCalc->setSourceSRS(srsid);
350+
351+
int myRed = settings.value("/qgis/default_measure_color_red", 180).toInt();
352+
int myGreen = settings.value("/qgis/default_measure_color_green", 180).toInt();
353+
int myBlue = settings.value("/qgis/default_measure_color_blue", 180).toInt();
354+
mRubberBand->setColor(QColor(myRed, myGreen, myBlue));
355+
340356
}
341357

342358
//////////////////////////

0 commit comments

Comments
 (0)
Please sign in to comment.