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;
59 return u
"geographiccoordinate"_s;
64 return QObject::tr(
"Geographic Coordinate" );
80 std::basic_stringstream<wchar_t> os;
88 return formatLatitude( value, os, context );
92 return formatLongitude( value, os, context );
104 auto res = std::make_unique< QgsGeographicCoordinateNumericFormat >();
107 res->mShowLeadingZeros =
configuration.value( u
"show_leading_zeros"_s,
false ).toBool();
108 res->mShowLeadingDegreeZeros =
configuration.value( u
"show_leading_degree_zeros"_s,
false ).toBool();
109 res->mUseSuffix =
configuration.value( u
"show_suffix"_s,
false ).toBool();
110 return res.release();
117 res.insert( u
"show_leading_zeros"_s, mShowLeadingZeros );
118 res.insert( u
"show_leading_degree_zeros"_s, mShowLeadingDegreeZeros );
119 res.insert( u
"show_suffix"_s, mUseSuffix );
130 mAngleFormat = format;
137 mShowLeadingZeros =
configuration.value( u
"show_leading_zeros"_s,
false ).toBool();
138 mShowLeadingDegreeZeros =
configuration.value( u
"show_leading_degree_zeros"_s,
false ).toBool();
139 mUseSuffix =
configuration.value( u
"show_suffix"_s,
false ).toBool();
144 return mShowLeadingZeros;
149 mShowLeadingZeros = newShowLeadingZeros;
154 return mShowLeadingDegreeZeros;
159 mShowLeadingDegreeZeros = show;
172QString QgsGeographicCoordinateNumericFormat::formatLongitude(
double value, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
174 switch ( mAngleFormat )
177 return formatLongitudeAsDegreesMinutesSeconds( value, ss, context );
179 return formatLongitudeAsDegreesMinutes( value, ss, context );
181 return formatLongitudeAsDegrees( value, ss, context );
186QString QgsGeographicCoordinateNumericFormat::formatLatitude(
double value, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
188 switch ( mAngleFormat )
191 return formatLatitudeAsDegreesMinutesSeconds( value, ss, context );
193 return formatLatitudeAsDegreesMinutes( value, ss, context );
195 return formatLatitudeAsDegrees( value, ss, context );
200QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegreesMinutesSeconds(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
203 double wrappedY = std::fmod( val, 180.0 );
205 if ( wrappedY > 90.0 )
207 wrappedY = wrappedY - 180.0;
209 else if ( wrappedY < -90.0 )
211 wrappedY = wrappedY + 180.0;
216 int degreesY = int( std::fabs( wrappedY ) );
217 const double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
218 int intMinutesY = int( floatMinutesY );
219 double secondsY = ( floatMinutesY - intMinutesY ) * 60.0;
222 if ( std::round( secondsY * precisionMultiplier ) >= 60 * precisionMultiplier )
224 secondsY = std::max( secondsY - 60, 0.0 );
226 if ( intMinutesY >= 60 )
237 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
248 if ( degreesY == 0 && intMinutesY == 0 && std::round( secondsY * precisionMultiplier ) == 0 )
257 ss << std::fixed << std::setprecision( 0 );
260 strMinutesY = QString::fromStdWString( ss.str() );
261 ss.str( std::wstring() );
265 strSecondsY = QString::fromStdWString( ss.str() );
266 ss.str( std::wstring() );
268 trimTrailingZeros( strSecondsY, context );
271 if ( mShowLeadingZeros && intMinutesY < 10 )
272 strMinutesY =
'0' + strMinutesY;
274 if ( mShowLeadingZeros && secondsY < 10 )
275 strSecondsY =
'0' + strSecondsY;
277 ss << std::fixed << std::setprecision( 0 );
279 QString degreesYStr = QString::fromStdWString( ss.str() );
280 ss.str( std::wstring() );
282 if ( mShowLeadingDegreeZeros )
283 degreesYStr = QString( u
"00"_s + degreesYStr ).right( 2 );
285 return sign + degreesYStr + QChar( 176 ) +
286 strMinutesY + QChar( 0x2032 ) +
287 strSecondsY + QChar( 0x2033 ) +
291QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegreesMinutesSeconds(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
294 double wrappedX = std::fmod( val, 360.0 );
296 if ( wrappedX > 180.0 )
298 wrappedX = wrappedX - 360.0;
300 else if ( wrappedX < -180.0 )
302 wrappedX = wrappedX + 360.0;
307 int degreesX = int( std::fabs( wrappedX ) );
308 const double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
309 int intMinutesX = int( floatMinutesX );
310 double secondsX = ( floatMinutesX - intMinutesX ) * 60.0;
313 if ( std::round( secondsX * precisionMultiplier ) >= 60 * precisionMultiplier )
315 secondsX = std::max( secondsX - 60, 0.0 );
317 if ( intMinutesX >= 60 )
328 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
339 if ( degreesX == 0 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
346 if ( degreesX == 180 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
354 ss << std::fixed << std::setprecision( 0 );
357 minutesX = QString::fromStdWString( ss.str() );
358 ss.str( std::wstring() );
362 strSecondsX = QString::fromStdWString( ss.str() );
363 ss.str( std::wstring() );
365 trimTrailingZeros( strSecondsX, context );
368 if ( mShowLeadingZeros && intMinutesX < 10 )
369 minutesX =
'0' + minutesX;
371 if ( mShowLeadingZeros && secondsX < 10 )
372 strSecondsX =
'0' + strSecondsX;
374 ss << std::fixed << std::setprecision( 0 );
376 QString degreesXStr = QString::fromStdWString( ss.str() );
377 ss.str( std::wstring() );
379 if ( mShowLeadingDegreeZeros )
380 degreesXStr = QString( u
"000"_s + degreesXStr ).right( 3 );
382 return sign + degreesXStr + QChar( 176 ) +
383 minutesX + QChar( 0x2032 ) +
384 strSecondsX + QChar( 0x2033 ) +
388QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegreesMinutes(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
391 double wrappedY = std::fmod( val, 180.0 );
393 if ( wrappedY > 90.0 )
395 wrappedY = wrappedY - 180.0;
397 else if ( wrappedY < -90.0 )
399 wrappedY = wrappedY + 180.0;
402 int degreesY = int( std::fabs( wrappedY ) );
403 double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
408 if ( std::round( floatMinutesY * precisionMultiplier ) >= 60 * precisionMultiplier )
410 floatMinutesY = std::max( floatMinutesY - 60, 0.0 );
418 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
429 if ( degreesY == 0 && std::round( floatMinutesY * precisionMultiplier ) == 0 )
437 QString strMinutesY = QString::fromStdWString( ss.str() );
438 ss.str( std::wstring() );
440 trimTrailingZeros( strMinutesY, context );
443 if ( mShowLeadingZeros && floatMinutesY < 10 )
444 strMinutesY =
'0' + strMinutesY;
446 ss << std::fixed << std::setprecision( 0 );
448 QString degreesYStr = QString::fromStdWString( ss.str() );
449 ss.str( std::wstring() );
451 if ( mShowLeadingDegreeZeros )
452 degreesYStr = QString( u
"00"_s + degreesYStr ).right( 2 );
454 return sign + degreesYStr + QChar( 176 ) +
455 strMinutesY + QChar( 0x2032 ) +
459QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegreesMinutes(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
462 double wrappedX = std::fmod( val, 360.0 );
464 if ( wrappedX > 180.0 )
466 wrappedX = wrappedX - 360.0;
468 else if ( wrappedX < -180.0 )
470 wrappedX = wrappedX + 360.0;
473 int degreesX = int( std::fabs( wrappedX ) );
474 double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
479 if ( std::round( floatMinutesX * precisionMultiplier ) >= 60 * precisionMultiplier )
481 floatMinutesX = std::max( floatMinutesX - 60, 0.0 );
489 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
500 if ( degreesX == 0 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
507 if ( degreesX == 180 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
514 QString strMinutesX = QString::fromStdWString( ss.str() );
515 ss.str( std::wstring() );
517 trimTrailingZeros( strMinutesX, context );
520 if ( mShowLeadingZeros && floatMinutesX < 10 )
521 strMinutesX =
'0' + strMinutesX;
523 ss << std::fixed << std::setprecision( 0 );
525 QString degreesXStr = QString::fromStdWString( ss.str() );
526 ss.str( std::wstring() );
528 if ( mShowLeadingDegreeZeros )
529 degreesXStr = QString( u
"000"_s + degreesXStr ).right( 3 );
531 return sign + degreesXStr + QChar( 176 ) +
532 strMinutesX + QChar( 0x2032 ) +
536QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegrees(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
539 double wrappedY = std::fmod( val, 180.0 );
541 if ( wrappedY > 90.0 )
543 wrappedY = wrappedY - 180.0;
545 else if ( wrappedY < -90.0 )
547 wrappedY = wrappedY + 180.0;
550 const double absY = std::fabs( wrappedY );
558 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
569 if ( std::round( absY * precisionMultiplier ) == 0 )
577 QString strDegreesY = QString::fromStdWString( ss.str() );
578 ss.str( std::wstring() );
580 trimTrailingZeros( strDegreesY, context );
582 if ( mShowLeadingDegreeZeros && absY < 10 )
583 strDegreesY =
'0' + strDegreesY;
585 return sign + strDegreesY + QChar( 176 ) + hemisphere;
588QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegrees(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
591 double wrappedX = std::fmod( val, 360.0 );
593 if ( wrappedX > 180.0 )
595 wrappedX = wrappedX - 360.0;
597 else if ( wrappedX < -180.0 )
599 wrappedX = wrappedX + 360.0;
602 const double absX = std::fabs( wrappedX );
610 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
621 if ( std::round( absX * precisionMultiplier ) == 0 )
628 if ( std::round( absX * precisionMultiplier ) == 180 * precisionMultiplier )
636 QString strDegreesX = QString::fromStdWString( ss.str() );
637 ss.str( std::wstring() );
639 trimTrailingZeros( strDegreesX, context );
641 if ( mShowLeadingDegreeZeros && absX < 100 )
642 strDegreesX =
'0' + strDegreesX;
643 if ( mShowLeadingDegreeZeros && absX < 10 )
644 strDegreesX =
'0' + strDegreesX;
646 return sign + strDegreesX + QChar( 176 ) + hemisphere;
649void QgsGeographicCoordinateNumericFormat::trimTrailingZeros( QString &input,
const QgsNumericFormatContext &context )
const
654 int trimPoint = input.length() - 1;
656 while ( input.at( trimPoint ) == context.
zeroDigit() )
659 if ( input.at( trimPoint ) == decimal )
662 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