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
3541QgsDistanceArea::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-
193178double 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
360372double 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