28#include "moc_qgscoordinatenumericformat.cpp"
30using namespace Qt::StringLiterals;
33namespace QgsGeographicCoordinateNumericFormat_ns
35 struct formatter : std::numpunct<wchar_t>
37 formatter( QChar thousands,
bool showThousands, QChar decimal )
38 : mThousands( thousands.unicode() )
39 , mDecimal( decimal.unicode() )
40 , mShowThousands( showThousands )
42 wchar_t do_decimal_point()
const override {
return mDecimal; }
43 wchar_t do_thousands_sep()
const override {
return mThousands; }
44 std::string do_grouping()
const override {
return mShowThousands ?
"\3" :
"\0"; }
48 bool mShowThousands =
true;
58 return u
"geographiccoordinate"_s;
63 return QObject::tr(
"Geographic Coordinate" );
79 std::basic_stringstream<wchar_t> os;
85 return formatLatitude( value, os, context );
89 return formatLongitude( value, os, context );
101 auto res = std::make_unique< QgsGeographicCoordinateNumericFormat >();
104 res->mShowLeadingZeros =
configuration.value( u
"show_leading_zeros"_s,
false ).toBool();
105 res->mShowLeadingDegreeZeros =
configuration.value( u
"show_leading_degree_zeros"_s,
false ).toBool();
106 res->mUseSuffix =
configuration.value( u
"show_suffix"_s,
false ).toBool();
107 return res.release();
114 res.insert( u
"show_leading_zeros"_s, mShowLeadingZeros );
115 res.insert( u
"show_leading_degree_zeros"_s, mShowLeadingDegreeZeros );
116 res.insert( u
"show_suffix"_s, mUseSuffix );
127 mAngleFormat = format;
134 mShowLeadingZeros =
configuration.value( u
"show_leading_zeros"_s,
false ).toBool();
135 mShowLeadingDegreeZeros =
configuration.value( u
"show_leading_degree_zeros"_s,
false ).toBool();
136 mUseSuffix =
configuration.value( u
"show_suffix"_s,
false ).toBool();
141 return mShowLeadingZeros;
146 mShowLeadingZeros = newShowLeadingZeros;
151 return mShowLeadingDegreeZeros;
156 mShowLeadingDegreeZeros = show;
169QString QgsGeographicCoordinateNumericFormat::formatLongitude(
double value, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
171 switch ( mAngleFormat )
174 return formatLongitudeAsDegreesMinutesSeconds( value, ss, context );
176 return formatLongitudeAsDegreesMinutes( value, ss, context );
178 return formatLongitudeAsDegrees( value, ss, context );
183QString QgsGeographicCoordinateNumericFormat::formatLatitude(
double value, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
185 switch ( mAngleFormat )
188 return formatLatitudeAsDegreesMinutesSeconds( value, ss, context );
190 return formatLatitudeAsDegreesMinutes( value, ss, context );
192 return formatLatitudeAsDegrees( value, ss, context );
197QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegreesMinutesSeconds(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
200 double wrappedY = std::fmod( val, 180.0 );
202 if ( wrappedY > 90.0 )
204 wrappedY = wrappedY - 180.0;
206 else if ( wrappedY < -90.0 )
208 wrappedY = wrappedY + 180.0;
213 int degreesY = int( std::fabs( wrappedY ) );
214 const double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
215 int intMinutesY = int( floatMinutesY );
216 double secondsY = ( floatMinutesY - intMinutesY ) * 60.0;
219 if ( std::round( secondsY * precisionMultiplier ) >= 60 * precisionMultiplier )
221 secondsY = std::max( secondsY - 60, 0.0 );
223 if ( intMinutesY >= 60 )
234 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
245 if ( degreesY == 0 && intMinutesY == 0 && std::round( secondsY * precisionMultiplier ) == 0 )
254 ss << std::fixed << std::setprecision( 0 );
257 strMinutesY = QString::fromStdWString( ss.str() );
258 ss.str( std::wstring() );
262 strSecondsY = QString::fromStdWString( ss.str() );
263 ss.str( std::wstring() );
265 trimTrailingZeros( strSecondsY, context );
268 if ( mShowLeadingZeros && intMinutesY < 10 )
269 strMinutesY =
'0' + strMinutesY;
271 if ( mShowLeadingZeros && secondsY < 10 )
272 strSecondsY =
'0' + strSecondsY;
274 ss << std::fixed << std::setprecision( 0 );
276 QString degreesYStr = QString::fromStdWString( ss.str() );
277 ss.str( std::wstring() );
279 if ( mShowLeadingDegreeZeros )
280 degreesYStr = QString( u
"00"_s + degreesYStr ).right( 2 );
282 return sign + degreesYStr + QChar( 176 ) + strMinutesY + QChar( 0x2032 ) + strSecondsY + QChar( 0x2033 ) + hemisphere;
285QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegreesMinutesSeconds(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
288 double wrappedX = std::fmod( val, 360.0 );
290 if ( wrappedX > 180.0 )
292 wrappedX = wrappedX - 360.0;
294 else if ( wrappedX < -180.0 )
296 wrappedX = wrappedX + 360.0;
301 int degreesX = int( std::fabs( wrappedX ) );
302 const double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
303 int intMinutesX = int( floatMinutesX );
304 double secondsX = ( floatMinutesX - intMinutesX ) * 60.0;
307 if ( std::round( secondsX * precisionMultiplier ) >= 60 * precisionMultiplier )
309 secondsX = std::max( secondsX - 60, 0.0 );
311 if ( intMinutesX >= 60 )
322 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
333 if ( degreesX == 0 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
340 if ( degreesX == 180 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
348 ss << std::fixed << std::setprecision( 0 );
351 minutesX = QString::fromStdWString( ss.str() );
352 ss.str( std::wstring() );
356 strSecondsX = QString::fromStdWString( ss.str() );
357 ss.str( std::wstring() );
359 trimTrailingZeros( strSecondsX, context );
362 if ( mShowLeadingZeros && intMinutesX < 10 )
363 minutesX =
'0' + minutesX;
365 if ( mShowLeadingZeros && secondsX < 10 )
366 strSecondsX =
'0' + strSecondsX;
368 ss << std::fixed << std::setprecision( 0 );
370 QString degreesXStr = QString::fromStdWString( ss.str() );
371 ss.str( std::wstring() );
373 if ( mShowLeadingDegreeZeros )
374 degreesXStr = QString( u
"000"_s + degreesXStr ).right( 3 );
376 return sign + degreesXStr + QChar( 176 ) + minutesX + QChar( 0x2032 ) + strSecondsX + QChar( 0x2033 ) + hemisphere;
379QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegreesMinutes(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
382 double wrappedY = std::fmod( val, 180.0 );
384 if ( wrappedY > 90.0 )
386 wrappedY = wrappedY - 180.0;
388 else if ( wrappedY < -90.0 )
390 wrappedY = wrappedY + 180.0;
393 int degreesY = int( std::fabs( wrappedY ) );
394 double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
399 if ( std::round( floatMinutesY * precisionMultiplier ) >= 60 * precisionMultiplier )
401 floatMinutesY = std::max( floatMinutesY - 60, 0.0 );
409 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
420 if ( degreesY == 0 && std::round( floatMinutesY * precisionMultiplier ) == 0 )
428 QString strMinutesY = QString::fromStdWString( ss.str() );
429 ss.str( std::wstring() );
431 trimTrailingZeros( strMinutesY, context );
434 if ( mShowLeadingZeros && floatMinutesY < 10 )
435 strMinutesY =
'0' + strMinutesY;
437 ss << std::fixed << std::setprecision( 0 );
439 QString degreesYStr = QString::fromStdWString( ss.str() );
440 ss.str( std::wstring() );
442 if ( mShowLeadingDegreeZeros )
443 degreesYStr = QString( u
"00"_s + degreesYStr ).right( 2 );
445 return sign + degreesYStr + QChar( 176 ) + strMinutesY + QChar( 0x2032 ) + hemisphere;
448QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegreesMinutes(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
451 double wrappedX = std::fmod( val, 360.0 );
453 if ( wrappedX > 180.0 )
455 wrappedX = wrappedX - 360.0;
457 else if ( wrappedX < -180.0 )
459 wrappedX = wrappedX + 360.0;
462 int degreesX = int( std::fabs( wrappedX ) );
463 double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
468 if ( std::round( floatMinutesX * precisionMultiplier ) >= 60 * precisionMultiplier )
470 floatMinutesX = std::max( floatMinutesX - 60, 0.0 );
478 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
489 if ( degreesX == 0 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
496 if ( degreesX == 180 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
503 QString strMinutesX = QString::fromStdWString( ss.str() );
504 ss.str( std::wstring() );
506 trimTrailingZeros( strMinutesX, context );
509 if ( mShowLeadingZeros && floatMinutesX < 10 )
510 strMinutesX =
'0' + strMinutesX;
512 ss << std::fixed << std::setprecision( 0 );
514 QString degreesXStr = QString::fromStdWString( ss.str() );
515 ss.str( std::wstring() );
517 if ( mShowLeadingDegreeZeros )
518 degreesXStr = QString( u
"000"_s + degreesXStr ).right( 3 );
520 return sign + degreesXStr + QChar( 176 ) + strMinutesX + QChar( 0x2032 ) + hemisphere;
523QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegrees(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
526 double wrappedY = std::fmod( val, 180.0 );
528 if ( wrappedY > 90.0 )
530 wrappedY = wrappedY - 180.0;
532 else if ( wrappedY < -90.0 )
534 wrappedY = wrappedY + 180.0;
537 const double absY = std::fabs( wrappedY );
545 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
556 if ( std::round( absY * precisionMultiplier ) == 0 )
564 QString strDegreesY = QString::fromStdWString( ss.str() );
565 ss.str( std::wstring() );
567 trimTrailingZeros( strDegreesY, context );
569 if ( mShowLeadingDegreeZeros && absY < 10 )
570 strDegreesY =
'0' + strDegreesY;
572 return sign + strDegreesY + QChar( 176 ) + hemisphere;
575QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegrees(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
578 double wrappedX = std::fmod( val, 360.0 );
580 if ( wrappedX > 180.0 )
582 wrappedX = wrappedX - 360.0;
584 else if ( wrappedX < -180.0 )
586 wrappedX = wrappedX + 360.0;
589 const double absX = std::fabs( wrappedX );
597 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
608 if ( std::round( absX * precisionMultiplier ) == 0 )
615 if ( std::round( absX * precisionMultiplier ) == 180 * precisionMultiplier )
623 QString strDegreesX = QString::fromStdWString( ss.str() );
624 ss.str( std::wstring() );
626 trimTrailingZeros( strDegreesX, context );
628 if ( mShowLeadingDegreeZeros && absX < 100 )
629 strDegreesX =
'0' + strDegreesX;
630 if ( mShowLeadingDegreeZeros && absX < 10 )
631 strDegreesX =
'0' + strDegreesX;
633 return sign + strDegreesX + QChar( 176 ) + hemisphere;
636void QgsGeographicCoordinateNumericFormat::trimTrailingZeros( QString &input,
const QgsNumericFormatContext &context )
const
641 int trimPoint = input.length() - 1;
643 while ( input.at( trimPoint ) == context.
zeroDigit() )
646 if ( input.at( trimPoint ) == decimal )
649 input.truncate( trimPoint + 1 );
A context for numeric formats.
QChar negativeSign() const
Returns the negative sign character.
QChar thousandsSeparator() const
Returns the thousands separator character.
QChar zeroDigit() const
Returns the zero digit character.
Interpretation interpretation() const
Returns the interpretation of the numbers being converted.
QChar decimalSeparator() const
Returns the decimal separator character.
@ Latitude
Latitude values.
@ Longitude
Longitude values.
A container for the context for various read/write operations on objects.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
#define BUILTIN_UNREACHABLE