QGIS API Documentation 3.99.0-Master (d270888f95f)
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 ) +
187 minutesX + QChar( 0x2032 ) +
188 strSecondsX + QChar( 0x2033 ) +
189 hemisphere;
190}
191
192QString QgsCoordinateFormatter::formatYAsDegreesMinutesSeconds( double val, int precision, FormatFlags flags )
193{
194 //first, limit latitude to -180 to 180 degree range
195 double wrappedY = std::fmod( val, 180.0 );
196 //next, wrap around latitudes > 90 or < -90 degrees, so that eg "110S" -> "70N"
197 if ( wrappedY > 90.0 )
198 {
199 wrappedY = wrappedY - 180.0;
200 }
201 else if ( wrappedY < -90.0 )
202 {
203 wrappedY = wrappedY + 180.0;
204 }
205
206 const double precisionMultiplier = std::pow( 10.0, precision );
207
208 int degreesY = int( std::fabs( wrappedY ) );
209 const double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
210 int intMinutesY = int( floatMinutesY );
211 double secondsY = ( floatMinutesY - intMinutesY ) * 60.0;
212
213 //make sure rounding to specified precision doesn't create seconds >= 60
214 if ( std::round( secondsY * precisionMultiplier ) >= 60 * precisionMultiplier )
215 {
216 secondsY = std::max( secondsY - 60, 0.0 );
217 intMinutesY++;
218 if ( intMinutesY >= 60 )
219 {
220 intMinutesY -= 60;
221 degreesY++;
222 }
223 }
224
225 QString hemisphere;
226 QString sign;
227 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
228 {
229 hemisphere = wrappedY < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
230 }
231 else
232 {
233 if ( wrappedY < 0 )
234 {
235 sign = QLocale().negativeSign();
236 }
237 }
238 //check if coordinate is all zeros for the specified precision, and if so,
239 //remove the sign and hemisphere strings
240 if ( degreesY == 0 && intMinutesY == 0 && std::round( secondsY * precisionMultiplier ) == 0 )
241 {
242 sign = QString();
243 hemisphere.clear();
244 }
245
246 QString strMinutesY;
247 QString strSecondsY;
248
249 //pad with leading digits if required
250 if ( flags.testFlag( FlagDegreesPadMinutesSeconds ) )
251 {
252 strMinutesY = QString( "%L1" ).arg( intMinutesY, 2, 10, QChar( '0' ) );
253 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
254 strSecondsY = QString( "%L1" ).arg( secondsY, digits, 'f', precision, QChar( '0' ) );
255 }
256 else
257 {
258 strMinutesY = QLocale().toString( intMinutesY );
259 strSecondsY = QLocale().toString( secondsY, 'f', precision );
260 }
261
262 return sign + QLocale().toString( degreesY ) + QChar( 176 ) +
263 strMinutesY + QChar( 0x2032 ) +
264 strSecondsY + QChar( 0x2033 ) +
265 hemisphere;
266}
267
268QString QgsCoordinateFormatter::formatXAsDegreesMinutes( double val, int precision, FormatFlags flags )
269{
270 //first, limit longitude to -360 to 360 degree range
271 double wrappedX = std::fmod( val, 360.0 );
272 //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
273 if ( wrappedX > 180.0 )
274 {
275 wrappedX = wrappedX - 360.0;
276 }
277 else if ( wrappedX < -180.0 )
278 {
279 wrappedX = wrappedX + 360.0;
280 }
281
282 int degreesX = int( std::fabs( wrappedX ) );
283 double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
284
285 const double precisionMultiplier = std::pow( 10.0, precision );
286
287 //make sure rounding to specified precision doesn't create minutes >= 60
288 if ( std::round( floatMinutesX * precisionMultiplier ) >= 60 * precisionMultiplier )
289 {
290 floatMinutesX = std::max( floatMinutesX - 60, 0.0 );
291 degreesX++;
292 }
293
294 QString hemisphere;
295 QString sign;
296 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
297 {
298 hemisphere = wrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
299 }
300 else
301 {
302 if ( wrappedX < 0 )
303 {
304 sign = QLocale().negativeSign();
305 }
306 }
307 //check if coordinate is all zeros for the specified precision, and if so,
308 //remove the sign and hemisphere strings
309 if ( degreesX == 0 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
310 {
311 sign.clear();
312 hemisphere.clear();
313 }
314
315 //also remove directional prefix from 180 degree longitudes
316 if ( degreesX == 180 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
317 {
318 hemisphere.clear();
319 }
320
321 //pad minutes with leading digits if required
322 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
323 const QString strMinutesX = flags.testFlag( FlagDegreesPadMinutesSeconds ) ? QString( "%1" ).arg( floatMinutesX, digits, 'f', precision, QChar( '0' ) )
324 : QLocale().toString( floatMinutesX, 'f', precision );
325
326 return sign + QLocale().toString( degreesX ) + QChar( 176 ) +
327 strMinutesX + QChar( 0x2032 ) +
328 hemisphere;
329}
330
331QString QgsCoordinateFormatter::formatYAsDegreesMinutes( double val, int precision, FormatFlags flags )
332{
333 //first, limit latitude to -180 to 180 degree range
334 double wrappedY = std::fmod( val, 180.0 );
335 //next, wrap around latitudes > 90 or < -90 degrees, so that eg "110S" -> "70N"
336 if ( wrappedY > 90.0 )
337 {
338 wrappedY = wrappedY - 180.0;
339 }
340 else if ( wrappedY < -90.0 )
341 {
342 wrappedY = wrappedY + 180.0;
343 }
344
345 int degreesY = int( std::fabs( wrappedY ) );
346 double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
347
348 const double precisionMultiplier = std::pow( 10.0, precision );
349
350 //make sure rounding to specified precision doesn't create minutes >= 60
351 if ( std::round( floatMinutesY * precisionMultiplier ) >= 60 * precisionMultiplier )
352 {
353 floatMinutesY = std::max( floatMinutesY - 60, 0.0 );
354 degreesY++;
355 }
356
357 QString hemisphere;
358 QString sign;
359 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
360 {
361 hemisphere = wrappedY < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
362 }
363 else
364 {
365 if ( wrappedY < 0 )
366 {
367 sign = QLocale().negativeSign();
368 }
369 }
370 //check if coordinate is all zeros for the specified precision, and if so,
371 //remove the sign and hemisphere strings
372 if ( degreesY == 0 && std::round( floatMinutesY * precisionMultiplier ) == 0 )
373 {
374 sign.clear();
375 hemisphere.clear();
376 }
377
378
379 //pad minutes with leading digits if required
380 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
381 const QString strMinutesY = flags.testFlag( FlagDegreesPadMinutesSeconds ) ? QString( "%1" ).arg( floatMinutesY, digits, 'f', precision, QChar( '0' ) )
382 : QLocale().toString( floatMinutesY, 'f', precision );
383
384 return sign + QLocale().toString( degreesY ) + QChar( 176 ) +
385 strMinutesY + QChar( 0x2032 ) +
386 hemisphere;
387}
388
389QString QgsCoordinateFormatter::formatXAsDegrees( double val, int precision, FormatFlags flags )
390{
391 //first, limit longitude to -360 to 360 degree range
392 double wrappedX = std::fmod( val, 360.0 );
393 //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
394 if ( wrappedX > 180.0 )
395 {
396 wrappedX = wrappedX - 360.0;
397 }
398 else if ( wrappedX < -180.0 )
399 {
400 wrappedX = wrappedX + 360.0;
401 }
402
403 const double absX = std::fabs( wrappedX );
404
405 const double precisionMultiplier = std::pow( 10.0, precision );
406
407 QString hemisphere;
408 QString sign;
409 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
410 {
411 hemisphere = wrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
412 }
413 else
414 {
415 if ( wrappedX < 0 )
416 {
417 sign = QLocale().negativeSign();
418 }
419 }
420 //check if coordinate is all zeros for the specified precision, and if so,
421 //remove the sign and hemisphere strings
422 if ( std::round( absX * precisionMultiplier ) == 0 )
423 {
424 sign.clear();
425 hemisphere.clear();
426 }
427
428 //also remove directional prefix from 180 degree longitudes
429 if ( std::round( absX * precisionMultiplier ) == 180 * precisionMultiplier )
430 {
431 sign.clear();
432 hemisphere.clear();
433 }
434
435 return sign + QLocale().toString( absX, 'f', precision ) + QChar( 176 ) + hemisphere;
436}
437
438QString QgsCoordinateFormatter::formatYAsDegrees( double val, int precision, FormatFlags flags )
439{
440 //first, limit latitude to -180 to 180 degree range
441 double wrappedY = std::fmod( val, 180.0 );
442 //next, wrap around latitudes > 90 or < -90 degrees, so that eg "110S" -> "70N"
443 if ( wrappedY > 90.0 )
444 {
445 wrappedY = wrappedY - 180.0;
446 }
447 else if ( wrappedY < -90.0 )
448 {
449 wrappedY = wrappedY + 180.0;
450 }
451
452 const double absY = std::fabs( wrappedY );
453
454 const double precisionMultiplier = std::pow( 10.0, precision );
455
456 QString hemisphere;
457 QString sign;
458 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
459 {
460 hemisphere = wrappedY < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
461 }
462 else
463 {
464 if ( wrappedY < 0 )
465 {
466 sign = QLocale().negativeSign();
467 }
468 }
469 //check if coordinate is all zeros for the specified precision, and if so,
470 //remove the sign and hemisphere strings
471 if ( std::round( absY * precisionMultiplier ) == 0 )
472 {
473 sign.clear();
474 hemisphere.clear();
475 }
476
477 return sign + QLocale().toString( absY, 'f', precision ) + QChar( 176 ) + hemisphere;
478}
CoordinateOrder
Order of coordinates.
Definition qgis.h:2460
@ XY
Easting/Northing (or Longitude/Latitude for geographic CRS).
Definition qgis.h:2462
@ Default
Respect the default axis ordering for the CRS, as defined in the CRS's parameters.
Definition qgis.h:2461
@ YX
Northing/Easting (or Latitude/Longitude for geographic CRS).
Definition qgis.h:2463
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:7489