QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
qgscoordinateformatter.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscoordinateformatter.cpp
3 --------------------------
4 begin : Decemeber 2015
5 copyright : (C) 2015 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgis.h"
21
22#include <QLocale>
23#include <QObject>
24#include <QString>
25
26using namespace Qt::StringLiterals;
27
29{
30 switch ( format )
31 {
32 case FormatPair:
33 return formatAsPair( x, precision );
34
36 return formatXAsDegreesMinutesSeconds( x, precision, flags );
37
39 return formatXAsDegreesMinutes( x, precision, flags );
40
42 return formatXAsDegrees( x, precision, flags );
43 }
44 return QString(); //avoid warnings
45}
46
48{
49 switch ( format )
50 {
51 case FormatPair:
52 return formatAsPair( y, precision );
53
55 return formatYAsDegreesMinutesSeconds( y, precision, flags );
56
58 return formatYAsDegreesMinutes( y, precision, flags );
59
61 return formatYAsDegrees( y, precision, flags );
62 }
63 return QString(); //avoid warnings
64}
65
67{
68 const QString formattedX = formatX( point.x(), format, precision, flags );
69 const QString formattedY = formatY( point.y(), format, precision, flags );
70
71 switch ( order )
72 {
75 return u"%1%2%3"_s.arg( formattedX, QgsCoordinateFormatter::separator(), formattedY );
76
78 return u"%1%2%3"_s.arg( formattedY, QgsCoordinateFormatter::separator(), formattedX );
79 }
81}
82
83QString QgsCoordinateFormatter::asPair( double x, double y, int precision, Qgis::CoordinateOrder order )
84{
85 const QString formattedX = formatAsPair( x, precision );
86 const QString formattedY = formatAsPair( y, precision );
87
88 switch ( order )
89 {
92 return u"%1%2%3"_s.arg( formattedX, QgsCoordinateFormatter::separator(), formattedY );
93
95 return u"%1%2%3"_s.arg( formattedY, QgsCoordinateFormatter::separator(), formattedX );
96 }
98}
99
101{
102 return QLocale().decimalPoint() == ','_L1 ? ' '_L1 : ','_L1;
103}
104
105QString QgsCoordinateFormatter::formatAsPair( double val, int precision )
106{
107 return std::isfinite( val ) ? QLocale().toString( val, 'f', precision ) : QObject::tr( "infinite" );
108}
109
110QString QgsCoordinateFormatter::formatXAsDegreesMinutesSeconds( double val, int precision, FormatFlags flags )
111{
112 //first, limit longitude to -360 to 360 degree range
113 double wrappedX = std::fmod( val, 360.0 );
114 //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
115 if ( wrappedX > 180.0 )
116 {
117 wrappedX = wrappedX - 360.0;
118 }
119 else if ( wrappedX < -180.0 )
120 {
121 wrappedX = wrappedX + 360.0;
122 }
123
124 const double precisionMultiplier = std::pow( 10.0, precision );
125
126 int degreesX = int( std::fabs( wrappedX ) );
127 const double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
128 int intMinutesX = int( floatMinutesX );
129 double secondsX = ( floatMinutesX - intMinutesX ) * 60.0;
130
131 //make sure rounding to specified precision doesn't create seconds >= 60
132 if ( std::round( secondsX * precisionMultiplier ) >= 60 * precisionMultiplier )
133 {
134 secondsX = std::max( secondsX - 60, 0.0 );
135 intMinutesX++;
136 if ( intMinutesX >= 60 )
137 {
138 intMinutesX -= 60;
139 degreesX++;
140 }
141 }
142
143 QString hemisphere;
144 QString sign;
145 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
146 {
147 hemisphere = wrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
148 }
149 else
150 {
151 if ( wrappedX < 0 )
152 {
153 sign = QLocale().negativeSign();
154 }
155 }
156 //check if coordinate is all zeros for the specified precision, and if so,
157 //remove the sign and hemisphere strings
158 if ( degreesX == 0 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
159 {
160 sign.clear();
161 hemisphere.clear();
162 }
163
164 //also remove directional prefix from 180 degree longitudes
165 if ( degreesX == 180 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
166 {
167 hemisphere.clear();
168 }
169
170 QString minutesX;
171 QString strSecondsX;
172
173 //pad with leading digits if required
174 if ( flags.testFlag( FlagDegreesPadMinutesSeconds ) )
175 {
176 minutesX = QString( "%L1" ).arg( intMinutesX, 2, 10, QChar( '0' ) );
177 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
178 strSecondsX = QString( "%L1" ).arg( secondsX, digits, 'f', precision, QChar( '0' ) );
179 }
180 else
181 {
182 minutesX = QLocale().toString( intMinutesX );
183 strSecondsX = QLocale().toString( secondsX, 'f', precision );
184 }
185
186 return sign + QLocale().toString( degreesX ) + QChar( 176 ) + minutesX + QChar( 0x2032 ) + strSecondsX + QChar( 0x2033 ) + hemisphere;
187}
188
189QString QgsCoordinateFormatter::formatYAsDegreesMinutesSeconds( double val, int precision, FormatFlags flags )
190{
191 //first, limit latitude to -180 to 180 degree range
192 double wrappedY = std::fmod( val, 180.0 );
193 //next, wrap around latitudes > 90 or < -90 degrees, so that eg "110S" -> "70N"
194 if ( wrappedY > 90.0 )
195 {
196 wrappedY = wrappedY - 180.0;
197 }
198 else if ( wrappedY < -90.0 )
199 {
200 wrappedY = wrappedY + 180.0;
201 }
202
203 const double precisionMultiplier = std::pow( 10.0, precision );
204
205 int degreesY = int( std::fabs( wrappedY ) );
206 const double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
207 int intMinutesY = int( floatMinutesY );
208 double secondsY = ( floatMinutesY - intMinutesY ) * 60.0;
209
210 //make sure rounding to specified precision doesn't create seconds >= 60
211 if ( std::round( secondsY * precisionMultiplier ) >= 60 * precisionMultiplier )
212 {
213 secondsY = std::max( secondsY - 60, 0.0 );
214 intMinutesY++;
215 if ( intMinutesY >= 60 )
216 {
217 intMinutesY -= 60;
218 degreesY++;
219 }
220 }
221
222 QString hemisphere;
223 QString sign;
224 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
225 {
226 hemisphere = wrappedY < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
227 }
228 else
229 {
230 if ( wrappedY < 0 )
231 {
232 sign = QLocale().negativeSign();
233 }
234 }
235 //check if coordinate is all zeros for the specified precision, and if so,
236 //remove the sign and hemisphere strings
237 if ( degreesY == 0 && intMinutesY == 0 && std::round( secondsY * precisionMultiplier ) == 0 )
238 {
239 sign = QString();
240 hemisphere.clear();
241 }
242
243 QString strMinutesY;
244 QString strSecondsY;
245
246 //pad with leading digits if required
247 if ( flags.testFlag( FlagDegreesPadMinutesSeconds ) )
248 {
249 strMinutesY = QString( "%L1" ).arg( intMinutesY, 2, 10, QChar( '0' ) );
250 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
251 strSecondsY = QString( "%L1" ).arg( secondsY, digits, 'f', precision, QChar( '0' ) );
252 }
253 else
254 {
255 strMinutesY = QLocale().toString( intMinutesY );
256 strSecondsY = QLocale().toString( secondsY, 'f', precision );
257 }
258
259 return sign + QLocale().toString( degreesY ) + QChar( 176 ) + strMinutesY + QChar( 0x2032 ) + strSecondsY + QChar( 0x2033 ) + hemisphere;
260}
261
262QString QgsCoordinateFormatter::formatXAsDegreesMinutes( double val, int precision, FormatFlags flags )
263{
264 //first, limit longitude to -360 to 360 degree range
265 double wrappedX = std::fmod( val, 360.0 );
266 //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
267 if ( wrappedX > 180.0 )
268 {
269 wrappedX = wrappedX - 360.0;
270 }
271 else if ( wrappedX < -180.0 )
272 {
273 wrappedX = wrappedX + 360.0;
274 }
275
276 int degreesX = int( std::fabs( wrappedX ) );
277 double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
278
279 const double precisionMultiplier = std::pow( 10.0, precision );
280
281 //make sure rounding to specified precision doesn't create minutes >= 60
282 if ( std::round( floatMinutesX * precisionMultiplier ) >= 60 * precisionMultiplier )
283 {
284 floatMinutesX = std::max( floatMinutesX - 60, 0.0 );
285 degreesX++;
286 }
287
288 QString hemisphere;
289 QString sign;
290 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
291 {
292 hemisphere = wrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
293 }
294 else
295 {
296 if ( wrappedX < 0 )
297 {
298 sign = QLocale().negativeSign();
299 }
300 }
301 //check if coordinate is all zeros for the specified precision, and if so,
302 //remove the sign and hemisphere strings
303 if ( degreesX == 0 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
304 {
305 sign.clear();
306 hemisphere.clear();
307 }
308
309 //also remove directional prefix from 180 degree longitudes
310 if ( degreesX == 180 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
311 {
312 hemisphere.clear();
313 }
314
315 //pad minutes with leading digits if required
316 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
317 const QString strMinutesX = flags.testFlag( FlagDegreesPadMinutesSeconds ) ? QString( "%1" ).arg( floatMinutesX, digits, 'f', precision, QChar( '0' ) )
318 : QLocale().toString( floatMinutesX, 'f', precision );
319
320 return sign + QLocale().toString( degreesX ) + QChar( 176 ) + strMinutesX + QChar( 0x2032 ) + hemisphere;
321}
322
323QString QgsCoordinateFormatter::formatYAsDegreesMinutes( double val, int precision, FormatFlags flags )
324{
325 //first, limit latitude to -180 to 180 degree range
326 double wrappedY = std::fmod( val, 180.0 );
327 //next, wrap around latitudes > 90 or < -90 degrees, so that eg "110S" -> "70N"
328 if ( wrappedY > 90.0 )
329 {
330 wrappedY = wrappedY - 180.0;
331 }
332 else if ( wrappedY < -90.0 )
333 {
334 wrappedY = wrappedY + 180.0;
335 }
336
337 int degreesY = int( std::fabs( wrappedY ) );
338 double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
339
340 const double precisionMultiplier = std::pow( 10.0, precision );
341
342 //make sure rounding to specified precision doesn't create minutes >= 60
343 if ( std::round( floatMinutesY * precisionMultiplier ) >= 60 * precisionMultiplier )
344 {
345 floatMinutesY = std::max( floatMinutesY - 60, 0.0 );
346 degreesY++;
347 }
348
349 QString hemisphere;
350 QString sign;
351 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
352 {
353 hemisphere = wrappedY < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
354 }
355 else
356 {
357 if ( wrappedY < 0 )
358 {
359 sign = QLocale().negativeSign();
360 }
361 }
362 //check if coordinate is all zeros for the specified precision, and if so,
363 //remove the sign and hemisphere strings
364 if ( degreesY == 0 && std::round( floatMinutesY * precisionMultiplier ) == 0 )
365 {
366 sign.clear();
367 hemisphere.clear();
368 }
369
370
371 //pad minutes with leading digits if required
372 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
373 const QString strMinutesY = flags.testFlag( FlagDegreesPadMinutesSeconds ) ? QString( "%1" ).arg( floatMinutesY, digits, 'f', precision, QChar( '0' ) )
374 : QLocale().toString( floatMinutesY, 'f', precision );
375
376 return sign + QLocale().toString( degreesY ) + QChar( 176 ) + strMinutesY + QChar( 0x2032 ) + hemisphere;
377}
378
379QString QgsCoordinateFormatter::formatXAsDegrees( double val, int precision, FormatFlags flags )
380{
381 //first, limit longitude to -360 to 360 degree range
382 double wrappedX = std::fmod( val, 360.0 );
383 //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
384 if ( wrappedX > 180.0 )
385 {
386 wrappedX = wrappedX - 360.0;
387 }
388 else if ( wrappedX < -180.0 )
389 {
390 wrappedX = wrappedX + 360.0;
391 }
392
393 const double absX = std::fabs( wrappedX );
394
395 const double precisionMultiplier = std::pow( 10.0, precision );
396
397 QString hemisphere;
398 QString sign;
399 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
400 {
401 hemisphere = wrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
402 }
403 else
404 {
405 if ( wrappedX < 0 )
406 {
407 sign = QLocale().negativeSign();
408 }
409 }
410 //check if coordinate is all zeros for the specified precision, and if so,
411 //remove the sign and hemisphere strings
412 if ( std::round( absX * precisionMultiplier ) == 0 )
413 {
414 sign.clear();
415 hemisphere.clear();
416 }
417
418 //also remove directional prefix from 180 degree longitudes
419 if ( std::round( absX * precisionMultiplier ) == 180 * precisionMultiplier )
420 {
421 sign.clear();
422 hemisphere.clear();
423 }
424
425 return sign + QLocale().toString( absX, 'f', precision ) + QChar( 176 ) + hemisphere;
426}
427
428QString QgsCoordinateFormatter::formatYAsDegrees( double val, int precision, FormatFlags flags )
429{
430 //first, limit latitude to -180 to 180 degree range
431 double wrappedY = std::fmod( val, 180.0 );
432 //next, wrap around latitudes > 90 or < -90 degrees, so that eg "110S" -> "70N"
433 if ( wrappedY > 90.0 )
434 {
435 wrappedY = wrappedY - 180.0;
436 }
437 else if ( wrappedY < -90.0 )
438 {
439 wrappedY = wrappedY + 180.0;
440 }
441
442 const double absY = std::fabs( wrappedY );
443
444 const double precisionMultiplier = std::pow( 10.0, precision );
445
446 QString hemisphere;
447 QString sign;
448 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
449 {
450 hemisphere = wrappedY < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
451 }
452 else
453 {
454 if ( wrappedY < 0 )
455 {
456 sign = QLocale().negativeSign();
457 }
458 }
459 //check if coordinate is all zeros for the specified precision, and if so,
460 //remove the sign and hemisphere strings
461 if ( std::round( absY * precisionMultiplier ) == 0 )
462 {
463 sign.clear();
464 hemisphere.clear();
465 }
466
467 return sign + QLocale().toString( absY, 'f', precision ) + QChar( 176 ) + hemisphere;
468}
CoordinateOrder
Order of coordinates.
Definition qgis.h:2484
@ XY
Easting/Northing (or Longitude/Latitude for geographic CRS).
Definition qgis.h:2486
@ Default
Respect the default axis ordering for the CRS, as defined in the CRS's parameters.
Definition qgis.h:2485
@ YX
Northing/Easting (or Latitude/Longitude for geographic CRS).
Definition qgis.h:2487
static QString asPair(double x, double y, int precision=12, Qgis::CoordinateOrder order=Qgis::CoordinateOrder::XY)
Formats coordinates as an "\a x,\a y" pair, with optional decimal precision (number of decimal places...
Format
Available formats for displaying coordinates.
@ FormatDecimalDegrees
Decimal degrees, eg 30.7555 degrees.
@ FormatPair
Formats coordinates as an "x,y" pair.
@ FormatDegreesMinutes
Degrees and decimal minutes, eg 30degrees 45.55'.
@ FormatDegreesMinutesSeconds
Degrees, minutes and seconds, eg 30 degrees 45'30".
static QString format(const QgsPointXY &point, Format format, int precision=12, FormatFlags flags=FlagDegreesUseStringSuffix, Qgis::CoordinateOrder order=Qgis::CoordinateOrder::XY)
Formats a point according to the specified parameters.
static QChar separator()
Returns the character used as X/Y separator, this is a , on locales that do not use ,...
static QString formatY(double y, Format format, int precision=12, FormatFlags flags=FlagDegreesUseStringSuffix)
Formats a y coordinate value according to the specified parameters.
QFlags< FormatFlag > FormatFlags
@ FlagDegreesUseStringSuffix
Include a direction suffix (eg 'N', 'E', 'S' or 'W'), otherwise a "-" prefix is used for west and sou...
@ FlagDegreesPadMinutesSeconds
Pad minute and second values with leading zeros, eg '05' instead of '5'.
static QString formatX(double x, Format format, int precision=12, FormatFlags flags=FlagDegreesUseStringSuffix)
Formats an x coordinate value according to the specified parameters.
Represents a 2D point.
Definition qgspointxy.h:62
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
#define BUILTIN_UNREACHABLE
Definition qgis.h:7540