QGIS API Documentation 3.99.0-Master (26c88405ac0)
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
26{
27 switch ( format )
28 {
29 case FormatPair:
30 return formatAsPair( x, precision );
31
33 return formatXAsDegreesMinutesSeconds( x, precision, flags );
34
36 return formatXAsDegreesMinutes( x, precision, flags );
37
39 return formatXAsDegrees( x, precision, flags );
40 }
41 return QString(); //avoid warnings
42}
43
45{
46 switch ( format )
47 {
48 case FormatPair:
49 return formatAsPair( y, precision );
50
52 return formatYAsDegreesMinutesSeconds( y, precision, flags );
53
55 return formatYAsDegreesMinutes( y, precision, flags );
56
58 return formatYAsDegrees( y, precision, flags );
59 }
60 return QString(); //avoid warnings
61}
62
64{
65 const QString formattedX = formatX( point.x(), format, precision, flags );
66 const QString formattedY = formatY( point.y(), format, precision, flags );
67
68 switch ( order )
69 {
72 return QStringLiteral( "%1%2%3" ).arg( formattedX, QgsCoordinateFormatter::separator(), formattedY );
73
75 return QStringLiteral( "%1%2%3" ).arg( formattedY, QgsCoordinateFormatter::separator(), formattedX );
76 }
78}
79
80QString QgsCoordinateFormatter::asPair( double x, double y, int precision, Qgis::CoordinateOrder order )
81{
82 const QString formattedX = formatAsPair( x, precision );
83 const QString formattedY = formatAsPair( y, precision );
84
85 switch ( order )
86 {
89 return QStringLiteral( "%1%2%3" ).arg( formattedX, QgsCoordinateFormatter::separator(), formattedY );
90
92 return QStringLiteral( "%1%2%3" ).arg( formattedY, QgsCoordinateFormatter::separator(), formattedX );
93 }
95}
96
98{
99 return QLocale().decimalPoint() == QLatin1Char( ',' ) ? QLatin1Char( ' ' ) : QLatin1Char( ',' );
100}
101
102QString QgsCoordinateFormatter::formatAsPair( double val, int precision )
103{
104 return std::isfinite( val ) ? QLocale().toString( val, 'f', precision ) : QObject::tr( "infinite" );
105}
106
107QString QgsCoordinateFormatter::formatXAsDegreesMinutesSeconds( double val, int precision, FormatFlags flags )
108{
109 //first, limit longitude to -360 to 360 degree range
110 double wrappedX = std::fmod( val, 360.0 );
111 //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
112 if ( wrappedX > 180.0 )
113 {
114 wrappedX = wrappedX - 360.0;
115 }
116 else if ( wrappedX < -180.0 )
117 {
118 wrappedX = wrappedX + 360.0;
119 }
120
121 const double precisionMultiplier = std::pow( 10.0, precision );
122
123 int degreesX = int( std::fabs( wrappedX ) );
124 const double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
125 int intMinutesX = int( floatMinutesX );
126 double secondsX = ( floatMinutesX - intMinutesX ) * 60.0;
127
128 //make sure rounding to specified precision doesn't create seconds >= 60
129 if ( std::round( secondsX * precisionMultiplier ) >= 60 * precisionMultiplier )
130 {
131 secondsX = std::max( secondsX - 60, 0.0 );
132 intMinutesX++;
133 if ( intMinutesX >= 60 )
134 {
135 intMinutesX -= 60;
136 degreesX++;
137 }
138 }
139
140 QString hemisphere;
141 QString sign;
142 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
143 {
144 hemisphere = wrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
145 }
146 else
147 {
148 if ( wrappedX < 0 )
149 {
150 sign = QLocale().negativeSign();
151 }
152 }
153 //check if coordinate is all zeros for the specified precision, and if so,
154 //remove the sign and hemisphere strings
155 if ( degreesX == 0 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
156 {
157 sign.clear();
158 hemisphere.clear();
159 }
160
161 //also remove directional prefix from 180 degree longitudes
162 if ( degreesX == 180 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
163 {
164 hemisphere.clear();
165 }
166
167 QString minutesX;
168 QString strSecondsX;
169
170 //pad with leading digits if required
171 if ( flags.testFlag( FlagDegreesPadMinutesSeconds ) )
172 {
173 minutesX = QString( "%L1" ).arg( intMinutesX, 2, 10, QChar( '0' ) );
174 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
175 strSecondsX = QString( "%L1" ).arg( secondsX, digits, 'f', precision, QChar( '0' ) );
176 }
177 else
178 {
179 minutesX = QLocale().toString( intMinutesX );
180 strSecondsX = QLocale().toString( secondsX, 'f', precision );
181 }
182
183 return sign + QLocale().toString( degreesX ) + QChar( 176 ) +
184 minutesX + QChar( 0x2032 ) +
185 strSecondsX + QChar( 0x2033 ) +
186 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 ) +
260 strMinutesY + QChar( 0x2032 ) +
261 strSecondsY + QChar( 0x2033 ) +
262 hemisphere;
263}
264
265QString QgsCoordinateFormatter::formatXAsDegreesMinutes( double val, int precision, FormatFlags flags )
266{
267 //first, limit longitude to -360 to 360 degree range
268 double wrappedX = std::fmod( val, 360.0 );
269 //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
270 if ( wrappedX > 180.0 )
271 {
272 wrappedX = wrappedX - 360.0;
273 }
274 else if ( wrappedX < -180.0 )
275 {
276 wrappedX = wrappedX + 360.0;
277 }
278
279 int degreesX = int( std::fabs( wrappedX ) );
280 double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
281
282 const double precisionMultiplier = std::pow( 10.0, precision );
283
284 //make sure rounding to specified precision doesn't create minutes >= 60
285 if ( std::round( floatMinutesX * precisionMultiplier ) >= 60 * precisionMultiplier )
286 {
287 floatMinutesX = std::max( floatMinutesX - 60, 0.0 );
288 degreesX++;
289 }
290
291 QString hemisphere;
292 QString sign;
293 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
294 {
295 hemisphere = wrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
296 }
297 else
298 {
299 if ( wrappedX < 0 )
300 {
301 sign = QLocale().negativeSign();
302 }
303 }
304 //check if coordinate is all zeros for the specified precision, and if so,
305 //remove the sign and hemisphere strings
306 if ( degreesX == 0 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
307 {
308 sign.clear();
309 hemisphere.clear();
310 }
311
312 //also remove directional prefix from 180 degree longitudes
313 if ( degreesX == 180 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
314 {
315 hemisphere.clear();
316 }
317
318 //pad minutes with leading digits if required
319 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
320 const QString strMinutesX = flags.testFlag( FlagDegreesPadMinutesSeconds ) ? QString( "%1" ).arg( floatMinutesX, digits, 'f', precision, QChar( '0' ) )
321 : QLocale().toString( floatMinutesX, 'f', precision );
322
323 return sign + QLocale().toString( degreesX ) + QChar( 176 ) +
324 strMinutesX + QChar( 0x2032 ) +
325 hemisphere;
326}
327
328QString QgsCoordinateFormatter::formatYAsDegreesMinutes( double val, int precision, FormatFlags flags )
329{
330 //first, limit latitude to -180 to 180 degree range
331 double wrappedY = std::fmod( val, 180.0 );
332 //next, wrap around latitudes > 90 or < -90 degrees, so that eg "110S" -> "70N"
333 if ( wrappedY > 90.0 )
334 {
335 wrappedY = wrappedY - 180.0;
336 }
337 else if ( wrappedY < -90.0 )
338 {
339 wrappedY = wrappedY + 180.0;
340 }
341
342 int degreesY = int( std::fabs( wrappedY ) );
343 double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
344
345 const double precisionMultiplier = std::pow( 10.0, precision );
346
347 //make sure rounding to specified precision doesn't create minutes >= 60
348 if ( std::round( floatMinutesY * precisionMultiplier ) >= 60 * precisionMultiplier )
349 {
350 floatMinutesY = std::max( floatMinutesY - 60, 0.0 );
351 degreesY++;
352 }
353
354 QString hemisphere;
355 QString sign;
356 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
357 {
358 hemisphere = wrappedY < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
359 }
360 else
361 {
362 if ( wrappedY < 0 )
363 {
364 sign = QLocale().negativeSign();
365 }
366 }
367 //check if coordinate is all zeros for the specified precision, and if so,
368 //remove the sign and hemisphere strings
369 if ( degreesY == 0 && std::round( floatMinutesY * precisionMultiplier ) == 0 )
370 {
371 sign.clear();
372 hemisphere.clear();
373 }
374
375
376 //pad minutes with leading digits if required
377 const int digits = 2 + ( precision == 0 ? 0 : 1 + precision ); //1 for decimal place if required
378 const QString strMinutesY = flags.testFlag( FlagDegreesPadMinutesSeconds ) ? QString( "%1" ).arg( floatMinutesY, digits, 'f', precision, QChar( '0' ) )
379 : QLocale().toString( floatMinutesY, 'f', precision );
380
381 return sign + QLocale().toString( degreesY ) + QChar( 176 ) +
382 strMinutesY + QChar( 0x2032 ) +
383 hemisphere;
384}
385
386QString QgsCoordinateFormatter::formatXAsDegrees( double val, int precision, FormatFlags flags )
387{
388 //first, limit longitude to -360 to 360 degree range
389 double wrappedX = std::fmod( val, 360.0 );
390 //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
391 if ( wrappedX > 180.0 )
392 {
393 wrappedX = wrappedX - 360.0;
394 }
395 else if ( wrappedX < -180.0 )
396 {
397 wrappedX = wrappedX + 360.0;
398 }
399
400 const double absX = std::fabs( wrappedX );
401
402 const double precisionMultiplier = std::pow( 10.0, precision );
403
404 QString hemisphere;
405 QString sign;
406 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
407 {
408 hemisphere = wrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
409 }
410 else
411 {
412 if ( wrappedX < 0 )
413 {
414 sign = QLocale().negativeSign();
415 }
416 }
417 //check if coordinate is all zeros for the specified precision, and if so,
418 //remove the sign and hemisphere strings
419 if ( std::round( absX * precisionMultiplier ) == 0 )
420 {
421 sign.clear();
422 hemisphere.clear();
423 }
424
425 //also remove directional prefix from 180 degree longitudes
426 if ( std::round( absX * precisionMultiplier ) == 180 * precisionMultiplier )
427 {
428 sign.clear();
429 hemisphere.clear();
430 }
431
432 return sign + QLocale().toString( absX, 'f', precision ) + QChar( 176 ) + hemisphere;
433}
434
435QString QgsCoordinateFormatter::formatYAsDegrees( double val, int precision, FormatFlags flags )
436{
437 //first, limit latitude to -180 to 180 degree range
438 double wrappedY = std::fmod( val, 180.0 );
439 //next, wrap around latitudes > 90 or < -90 degrees, so that eg "110S" -> "70N"
440 if ( wrappedY > 90.0 )
441 {
442 wrappedY = wrappedY - 180.0;
443 }
444 else if ( wrappedY < -90.0 )
445 {
446 wrappedY = wrappedY + 180.0;
447 }
448
449 const double absY = std::fabs( wrappedY );
450
451 const double precisionMultiplier = std::pow( 10.0, precision );
452
453 QString hemisphere;
454 QString sign;
455 if ( flags.testFlag( FlagDegreesUseStringSuffix ) )
456 {
457 hemisphere = wrappedY < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
458 }
459 else
460 {
461 if ( wrappedY < 0 )
462 {
463 sign = QLocale().negativeSign();
464 }
465 }
466 //check if coordinate is all zeros for the specified precision, and if so,
467 //remove the sign and hemisphere strings
468 if ( std::round( absY * precisionMultiplier ) == 0 )
469 {
470 sign.clear();
471 hemisphere.clear();
472 }
473
474 return sign + QLocale().toString( absY, 'f', precision ) + QChar( 176 ) + hemisphere;
475}
CoordinateOrder
Order of coordinates.
Definition qgis.h:2402
@ XY
Easting/Northing (or Longitude/Latitude for geographic CRS).
Definition qgis.h:2404
@ Default
Respect the default axis ordering for the CRS, as defined in the CRS's parameters.
Definition qgis.h:2403
@ YX
Northing/Easting (or Latitude/Longitude for geographic CRS).
Definition qgis.h:2405
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:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
#define BUILTIN_UNREACHABLE
Definition qgis.h:7208