17
17
#include < cmath>
18
18
#include < sqlite3.h>
19
19
#include < QDir>
20
- #include < QSettings>
20
+ #include < QString>
21
+ #include < QLocale>
22
+ #include < QObject>
21
23
22
24
#include " qgis.h"
23
25
#include " qgspoint.h"
24
- #include " qgsproject.h"
25
26
#include " qgscoordinatetransform.h"
26
27
#include " qgsspatialrefsys.h"
27
28
#include " qgsgeometry.h"
28
29
#include " qgsdistancearea.h"
29
30
#include " qgsapplication.h"
30
31
#include " qgslogger.h"
31
32
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
+
32
38
#define DEG2RAD (x ) ((x)*M_PI/180 )
33
39
34
40
35
41
QgsDistanceArea::QgsDistanceArea ()
36
42
{
37
43
// init with default settings
44
+ mProjectionsEnabled = FALSE ;
38
45
mCoordTransform = new QgsCoordinateTransform;
39
- setDefaultEllipsoid ();
40
- setProjectAsSourceSRS ( );
46
+ setSourceSRS (GEOSRS_ID); // WGS 84
47
+ setEllipsoid ( " WGS84 " );
41
48
}
42
49
43
50
@@ -47,27 +54,17 @@ QgsDistanceArea::~QgsDistanceArea()
47
54
}
48
55
49
56
50
- void QgsDistanceArea::setSourceSRS ( long srsid )
57
+ void QgsDistanceArea::setProjectionsEnabled ( bool flag )
51
58
{
52
- QgsSpatialRefSys srcSRS;
53
- srcSRS.createFromSrsId (srsid);
54
- mCoordTransform ->setSourceSRS (srcSRS);
59
+ mProjectionsEnabled = flag;
55
60
}
56
61
57
62
58
- void QgsDistanceArea::setProjectAsSourceSRS ( )
63
+ void QgsDistanceArea::setSourceSRS ( long srsid )
59
64
{
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);
71
68
}
72
69
73
70
@@ -81,6 +78,14 @@ bool QgsDistanceArea::setEllipsoid(const QString& ellipsoid)
81
78
const char *myTail;
82
79
sqlite3_stmt *myPreparedStatement;
83
80
int myResult;
81
+
82
+ // Shortcut if ellipsoid is none.
83
+ if (ellipsoid == " NONE" )
84
+ {
85
+ mEllipsoid = " NONE" ;
86
+ return true ;
87
+ }
88
+
84
89
// check the db is available
85
90
myResult = sqlite3_open (QString (QgsApplication::qgisUserDbFilePath ()).latin1 (), &myDatabase);
86
91
if (myResult)
@@ -170,26 +175,6 @@ bool QgsDistanceArea::setEllipsoid(const QString& ellipsoid)
170
175
}
171
176
172
177
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
-
193
178
double QgsDistanceArea::measure (QgsGeometry* geometry)
194
179
{
195
180
unsigned char * wkb = geometry->wkbBuffer ();
@@ -246,6 +231,7 @@ unsigned char* QgsDistanceArea::measureLine(unsigned char* feature, double* area
246
231
247
232
std::vector<QgsPoint> points (nPoints);
248
233
234
+ QgsDebugMsg (" This feature WKB has " + QString::number (nPoints) + " points" );
249
235
// Extract the points from the WKB format into the vector
250
236
for (unsigned int i = 0 ; i < nPoints; ++i)
251
237
{
@@ -265,18 +251,32 @@ double QgsDistanceArea::measureLine(const std::vector<QgsPoint>& points)
265
251
if (points.size () < 2 )
266
252
return 0 ;
267
253
254
+ double total = 0 ;
255
+ QgsPoint p1, p2;
256
+
268
257
try
269
258
{
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++)
275
265
{
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
+
278
277
p1 = p2;
279
278
}
279
+
280
280
return total;
281
281
}
282
282
catch (QgsCsException &cse)
@@ -291,9 +291,17 @@ double QgsDistanceArea::measureLine(const QgsPoint& p1, const QgsPoint& p2)
291
291
{
292
292
try
293
293
{
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
+ }
297
305
}
298
306
catch (QgsCsException &cse)
299
307
{
@@ -328,14 +336,18 @@ unsigned char* QgsDistanceArea::measurePolygon(unsigned char* feature, double* a
328
336
329
337
// Extract the points from the WKB and store in a pair of
330
338
// vectors.
331
- for (unsigned int jdx = 0 ; jdx < nPoints; jdx++)
339
+ for (int jdx = 0 ; jdx < nPoints; jdx++)
332
340
{
333
341
x = *((double *) ptr);
334
342
ptr += sizeof (double );
335
343
y = *((double *) ptr);
336
344
ptr += sizeof (double );
337
345
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
+ }
339
351
}
340
352
341
353
if (points.size () > 2 )
@@ -359,14 +371,22 @@ unsigned char* QgsDistanceArea::measurePolygon(unsigned char* feature, double* a
359
371
360
372
double QgsDistanceArea::measurePolygon (const std::vector<QgsPoint>& points)
361
373
{
374
+
362
375
try
363
376
{
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" ))
366
378
{
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);
368
389
}
369
- return computePolygonArea (pts);
370
390
}
371
391
catch (QgsCsException &cse)
372
392
{
@@ -376,6 +396,20 @@ double QgsDistanceArea::measurePolygon(const std::vector<QgsPoint>& points)
376
396
}
377
397
378
398
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
+
379
413
380
414
// /////////////////////////////////////////////////////////
381
415
// distance calculation
@@ -512,6 +546,11 @@ double QgsDistanceArea::computePolygonArea(const std::vector<QgsPoint>& points)
512
546
double Qbar1, Qbar2;
513
547
double area;
514
548
549
+ QgsDebugMsg (" Ellipsoid: " + mEllipsoid );
550
+ if ((! mProjectionsEnabled ) || (mEllipsoid == " NONE" ))
551
+ {
552
+ return computePolygonFlatArea (points);
553
+ }
515
554
int n = points.size ();
516
555
x2 = DEG2RAD (points[n-1 ].x ());
517
556
y2 = DEG2RAD (points[n-1 ].y ());
@@ -556,3 +595,131 @@ double QgsDistanceArea::computePolygonArea(const std::vector<QgsPoint>& points)
556
595
return area;
557
596
}
558
597
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