26#include "moc_qgscoordinatenumericformat.cpp"
29namespace QgsGeographicCoordinateNumericFormat_ns
31 struct formatter : std::numpunct<wchar_t>
33 formatter( QChar thousands,
bool showThousands, QChar decimal )
34 : mThousands( thousands.unicode() )
35 , mDecimal( decimal.unicode() )
36 , mShowThousands( showThousands )
38 wchar_t do_decimal_point()
const override {
return mDecimal; }
39 wchar_t do_thousands_sep()
const override {
return mThousands; }
40 std::string do_grouping()
const override {
return mShowThousands ?
"\3" :
"\0"; }
44 bool mShowThousands =
true;
55 return QStringLiteral(
"geographiccoordinate" );
60 return QObject::tr(
"Geographic Coordinate" );
76 std::basic_stringstream<wchar_t> os;
84 return formatLatitude( value, os, context );
88 return formatLongitude( value, os, context );
100 auto res = std::make_unique< QgsGeographicCoordinateNumericFormat >();
103 res->mShowLeadingZeros =
configuration.value( QStringLiteral(
"show_leading_zeros" ),
false ).toBool();
104 res->mShowLeadingDegreeZeros =
configuration.value( QStringLiteral(
"show_leading_degree_zeros" ),
false ).toBool();
105 res->mUseSuffix =
configuration.value( QStringLiteral(
"show_suffix" ),
false ).toBool();
106 return res.release();
112 res.insert( QStringLiteral(
"angle_format" ),
qgsEnumValueToKey( mAngleFormat ) );
113 res.insert( QStringLiteral(
"show_leading_zeros" ), mShowLeadingZeros );
114 res.insert( QStringLiteral(
"show_leading_degree_zeros" ), mShowLeadingDegreeZeros );
115 res.insert( QStringLiteral(
"show_suffix" ), mUseSuffix );
126 mAngleFormat = format;
133 mShowLeadingZeros =
configuration.value( QStringLiteral(
"show_leading_zeros" ),
false ).toBool();
134 mShowLeadingDegreeZeros =
configuration.value( QStringLiteral(
"show_leading_degree_zeros" ),
false ).toBool();
135 mUseSuffix =
configuration.value( QStringLiteral(
"show_suffix" ),
false ).toBool();
140 return mShowLeadingZeros;
145 mShowLeadingZeros = newShowLeadingZeros;
150 return mShowLeadingDegreeZeros;
155 mShowLeadingDegreeZeros = show;
168QString QgsGeographicCoordinateNumericFormat::formatLongitude(
double value, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
170 switch ( mAngleFormat )
173 return formatLongitudeAsDegreesMinutesSeconds( value, ss, context );
175 return formatLongitudeAsDegreesMinutes( value, ss, context );
177 return formatLongitudeAsDegrees( value, ss, context );
182QString QgsGeographicCoordinateNumericFormat::formatLatitude(
double value, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
184 switch ( mAngleFormat )
187 return formatLatitudeAsDegreesMinutesSeconds( value, ss, context );
189 return formatLatitudeAsDegreesMinutes( value, ss, context );
191 return formatLatitudeAsDegrees( value, ss, context );
196QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegreesMinutesSeconds(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
199 double wrappedY = std::fmod( val, 180.0 );
201 if ( wrappedY > 90.0 )
203 wrappedY = wrappedY - 180.0;
205 else if ( wrappedY < -90.0 )
207 wrappedY = wrappedY + 180.0;
212 int degreesY = int( std::fabs( wrappedY ) );
213 const double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
214 int intMinutesY = int( floatMinutesY );
215 double secondsY = ( floatMinutesY - intMinutesY ) * 60.0;
218 if ( std::round( secondsY * precisionMultiplier ) >= 60 * precisionMultiplier )
220 secondsY = std::max( secondsY - 60, 0.0 );
222 if ( intMinutesY >= 60 )
233 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
244 if ( degreesY == 0 && intMinutesY == 0 && std::round( secondsY * precisionMultiplier ) == 0 )
253 ss << std::fixed << std::setprecision( 0 );
256 strMinutesY = QString::fromStdWString( ss.str() );
257 ss.str( std::wstring() );
261 strSecondsY = QString::fromStdWString( ss.str() );
262 ss.str( std::wstring() );
264 trimTrailingZeros( strSecondsY, context );
267 if ( mShowLeadingZeros && intMinutesY < 10 )
268 strMinutesY =
'0' + strMinutesY;
270 if ( mShowLeadingZeros && secondsY < 10 )
271 strSecondsY =
'0' + strSecondsY;
273 ss << std::fixed << std::setprecision( 0 );
275 QString degreesYStr = QString::fromStdWString( ss.str() );
276 ss.str( std::wstring() );
278 if ( mShowLeadingDegreeZeros )
279 degreesYStr = QString( QStringLiteral(
"00" ) + degreesYStr ).right( 2 );
281 return sign + degreesYStr + QChar( 176 ) +
282 strMinutesY + QChar( 0x2032 ) +
283 strSecondsY + QChar( 0x2033 ) +
287QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegreesMinutesSeconds(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
290 double wrappedX = std::fmod( val, 360.0 );
292 if ( wrappedX > 180.0 )
294 wrappedX = wrappedX - 360.0;
296 else if ( wrappedX < -180.0 )
298 wrappedX = wrappedX + 360.0;
303 int degreesX = int( std::fabs( wrappedX ) );
304 const double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
305 int intMinutesX = int( floatMinutesX );
306 double secondsX = ( floatMinutesX - intMinutesX ) * 60.0;
309 if ( std::round( secondsX * precisionMultiplier ) >= 60 * precisionMultiplier )
311 secondsX = std::max( secondsX - 60, 0.0 );
313 if ( intMinutesX >= 60 )
324 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
335 if ( degreesX == 0 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
342 if ( degreesX == 180 && intMinutesX == 0 && std::round( secondsX * precisionMultiplier ) == 0 )
350 ss << std::fixed << std::setprecision( 0 );
353 minutesX = QString::fromStdWString( ss.str() );
354 ss.str( std::wstring() );
358 strSecondsX = QString::fromStdWString( ss.str() );
359 ss.str( std::wstring() );
361 trimTrailingZeros( strSecondsX, context );
364 if ( mShowLeadingZeros && intMinutesX < 10 )
365 minutesX =
'0' + minutesX;
367 if ( mShowLeadingZeros && secondsX < 10 )
368 strSecondsX =
'0' + strSecondsX;
370 ss << std::fixed << std::setprecision( 0 );
372 QString degreesXStr = QString::fromStdWString( ss.str() );
373 ss.str( std::wstring() );
375 if ( mShowLeadingDegreeZeros )
376 degreesXStr = QString( QStringLiteral(
"000" ) + degreesXStr ).right( 3 );
378 return sign + degreesXStr + QChar( 176 ) +
379 minutesX + QChar( 0x2032 ) +
380 strSecondsX + QChar( 0x2033 ) +
384QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegreesMinutes(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
387 double wrappedY = std::fmod( val, 180.0 );
389 if ( wrappedY > 90.0 )
391 wrappedY = wrappedY - 180.0;
393 else if ( wrappedY < -90.0 )
395 wrappedY = wrappedY + 180.0;
398 int degreesY = int( std::fabs( wrappedY ) );
399 double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
404 if ( std::round( floatMinutesY * precisionMultiplier ) >= 60 * precisionMultiplier )
406 floatMinutesY = std::max( floatMinutesY - 60, 0.0 );
414 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
425 if ( degreesY == 0 && std::round( floatMinutesY * precisionMultiplier ) == 0 )
433 QString strMinutesY = QString::fromStdWString( ss.str() );
434 ss.str( std::wstring() );
436 trimTrailingZeros( strMinutesY, context );
439 if ( mShowLeadingZeros && floatMinutesY < 10 )
440 strMinutesY =
'0' + strMinutesY;
442 ss << std::fixed << std::setprecision( 0 );
444 QString degreesYStr = QString::fromStdWString( ss.str() );
445 ss.str( std::wstring() );
447 if ( mShowLeadingDegreeZeros )
448 degreesYStr = QString( QStringLiteral(
"00" ) + degreesYStr ).right( 2 );
450 return sign + degreesYStr + QChar( 176 ) +
451 strMinutesY + QChar( 0x2032 ) +
455QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegreesMinutes(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
458 double wrappedX = std::fmod( val, 360.0 );
460 if ( wrappedX > 180.0 )
462 wrappedX = wrappedX - 360.0;
464 else if ( wrappedX < -180.0 )
466 wrappedX = wrappedX + 360.0;
469 int degreesX = int( std::fabs( wrappedX ) );
470 double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
475 if ( std::round( floatMinutesX * precisionMultiplier ) >= 60 * precisionMultiplier )
477 floatMinutesX = std::max( floatMinutesX - 60, 0.0 );
485 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
496 if ( degreesX == 0 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
503 if ( degreesX == 180 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
510 QString strMinutesX = QString::fromStdWString( ss.str() );
511 ss.str( std::wstring() );
513 trimTrailingZeros( strMinutesX, context );
516 if ( mShowLeadingZeros && floatMinutesX < 10 )
517 strMinutesX =
'0' + strMinutesX;
519 ss << std::fixed << std::setprecision( 0 );
521 QString degreesXStr = QString::fromStdWString( ss.str() );
522 ss.str( std::wstring() );
524 if ( mShowLeadingDegreeZeros )
525 degreesXStr = QString( QStringLiteral(
"000" ) + degreesXStr ).right( 3 );
527 return sign + degreesXStr + QChar( 176 ) +
528 strMinutesX + QChar( 0x2032 ) +
532QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegrees(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
535 double wrappedY = std::fmod( val, 180.0 );
537 if ( wrappedY > 90.0 )
539 wrappedY = wrappedY - 180.0;
541 else if ( wrappedY < -90.0 )
543 wrappedY = wrappedY + 180.0;
546 const double absY = std::fabs( wrappedY );
554 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
565 if ( std::round( absY * precisionMultiplier ) == 0 )
573 QString strDegreesY = QString::fromStdWString( ss.str() );
574 ss.str( std::wstring() );
576 trimTrailingZeros( strDegreesY, context );
578 if ( mShowLeadingDegreeZeros && absY < 10 )
579 strDegreesY =
'0' + strDegreesY;
581 return sign + strDegreesY + QChar( 176 ) + hemisphere;
584QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegrees(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
587 double wrappedX = std::fmod( val, 360.0 );
589 if ( wrappedX > 180.0 )
591 wrappedX = wrappedX - 360.0;
593 else if ( wrappedX < -180.0 )
595 wrappedX = wrappedX + 360.0;
598 const double absX = std::fabs( wrappedX );
606 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
617 if ( std::round( absX * precisionMultiplier ) == 0 )
624 if ( std::round( absX * precisionMultiplier ) == 180 * precisionMultiplier )
632 QString strDegreesX = QString::fromStdWString( ss.str() );
633 ss.str( std::wstring() );
635 trimTrailingZeros( strDegreesX, context );
637 if ( mShowLeadingDegreeZeros && absX < 100 )
638 strDegreesX =
'0' + strDegreesX;
639 if ( mShowLeadingDegreeZeros && absX < 10 )
640 strDegreesX =
'0' + strDegreesX;
642 return sign + strDegreesX + QChar( 176 ) + hemisphere;
645void QgsGeographicCoordinateNumericFormat::trimTrailingZeros( QString &input,
const QgsNumericFormatContext &context )
const
650 int trimPoint = input.length() - 1;
652 while ( input.at( trimPoint ) == context.
zeroDigit() )
655 if ( input.at( trimPoint ) == decimal )
658 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