17#include "moc_qgscoordinatenumericformat.cpp"
27namespace QgsGeographicCoordinateNumericFormat_ns
29 struct formatter : std::numpunct<wchar_t>
31 formatter( QChar thousands,
bool showThousands, QChar decimal )
32 : mThousands( thousands.unicode() )
33 , mDecimal( decimal.unicode() )
34 , mShowThousands( showThousands )
36 wchar_t do_decimal_point()
const override {
return mDecimal; }
37 wchar_t do_thousands_sep()
const override {
return mThousands; }
38 std::string do_grouping()
const override {
return mShowThousands ?
"\3" :
"\0"; }
42 bool mShowThousands =
true;
53 return QStringLiteral(
"geographiccoordinate" );
58 return QObject::tr(
"Geographic Coordinate" );
74 std::basic_stringstream<wchar_t> os;
82 return formatLatitude( value, os, context );
86 return formatLongitude( value, os, context );
98 std::unique_ptr< QgsGeographicCoordinateNumericFormat > res = std::make_unique< QgsGeographicCoordinateNumericFormat >();
101 res->mShowLeadingZeros =
configuration.value( QStringLiteral(
"show_leading_zeros" ),
false ).toBool();
102 res->mShowLeadingDegreeZeros =
configuration.value( QStringLiteral(
"show_leading_degree_zeros" ),
false ).toBool();
103 res->mUseSuffix =
configuration.value( QStringLiteral(
"show_suffix" ),
false ).toBool();
104 return res.release();
110 res.insert( QStringLiteral(
"angle_format" ),
qgsEnumValueToKey( mAngleFormat ) );
111 res.insert( QStringLiteral(
"show_leading_zeros" ), mShowLeadingZeros );
112 res.insert( QStringLiteral(
"show_leading_degree_zeros" ), mShowLeadingDegreeZeros );
113 res.insert( QStringLiteral(
"show_suffix" ), mUseSuffix );
124 mAngleFormat = format;
131 mShowLeadingZeros =
configuration.value( QStringLiteral(
"show_leading_zeros" ),
false ).toBool();
132 mShowLeadingDegreeZeros =
configuration.value( QStringLiteral(
"show_leading_degree_zeros" ),
false ).toBool();
133 mUseSuffix =
configuration.value( QStringLiteral(
"show_suffix" ),
false ).toBool();
138 return mShowLeadingZeros;
143 mShowLeadingZeros = newShowLeadingZeros;
148 return mShowLeadingDegreeZeros;
153 mShowLeadingDegreeZeros = show;
166QString QgsGeographicCoordinateNumericFormat::formatLongitude(
double value, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
168 switch ( mAngleFormat )
171 return formatLongitudeAsDegreesMinutesSeconds( value, ss, context );
173 return formatLongitudeAsDegreesMinutes( value, ss, context );
175 return formatLongitudeAsDegrees( value, ss, context );
180QString QgsGeographicCoordinateNumericFormat::formatLatitude(
double value, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
182 switch ( mAngleFormat )
185 return formatLatitudeAsDegreesMinutesSeconds( value, ss, context );
187 return formatLatitudeAsDegreesMinutes( value, ss, context );
189 return formatLatitudeAsDegrees( value, ss, context );
194QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegreesMinutesSeconds(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
197 double wrappedY = std::fmod( val, 180.0 );
199 if ( wrappedY > 90.0 )
201 wrappedY = wrappedY - 180.0;
203 else if ( wrappedY < -90.0 )
205 wrappedY = wrappedY + 180.0;
210 int degreesY = int( std::fabs( wrappedY ) );
211 const double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
212 int intMinutesY = int( floatMinutesY );
213 double secondsY = ( floatMinutesY - intMinutesY ) * 60.0;
216 if ( std::round( secondsY * precisionMultiplier ) >= 60 * precisionMultiplier )
218 secondsY = std::max( secondsY - 60, 0.0 );
220 if ( intMinutesY >= 60 )
231 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
242 if ( degreesY == 0 && intMinutesY == 0 && std::round( secondsY * precisionMultiplier ) == 0 )
251 ss << std::fixed << std::setprecision( 0 );
254 strMinutesY = QString::fromStdWString( ss.str() );
255 ss.str( std::wstring() );
259 strSecondsY = QString::fromStdWString( ss.str() );
260 ss.str( std::wstring() );
262 trimTrailingZeros( strSecondsY, context );
265 if ( mShowLeadingZeros && intMinutesY < 10 )
266 strMinutesY =
'0' + strMinutesY;
268 if ( mShowLeadingZeros && secondsY < 10 )
269 strSecondsY =
'0' + strSecondsY;
271 ss << std::fixed << std::setprecision( 0 );
273 QString degreesYStr = QString::fromStdWString( ss.str() );
274 ss.str( std::wstring() );
276 if ( mShowLeadingDegreeZeros )
277 degreesYStr = QString( QStringLiteral(
"00" ) + degreesYStr ).right( 2 );
279 return sign + degreesYStr + QChar( 176 ) +
280 strMinutesY + QChar( 0x2032 ) +
281 strSecondsY + QChar( 0x2033 ) +
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( QStringLiteral(
"000" ) + degreesXStr ).right( 3 );
376 return sign + degreesXStr + QChar( 176 ) +
377 minutesX + QChar( 0x2032 ) +
378 strSecondsX + QChar( 0x2033 ) +
382QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegreesMinutes(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
385 double wrappedY = std::fmod( val, 180.0 );
387 if ( wrappedY > 90.0 )
389 wrappedY = wrappedY - 180.0;
391 else if ( wrappedY < -90.0 )
393 wrappedY = wrappedY + 180.0;
396 int degreesY = int( std::fabs( wrappedY ) );
397 double floatMinutesY = ( std::fabs( wrappedY ) - degreesY ) * 60.0;
402 if ( std::round( floatMinutesY * precisionMultiplier ) >= 60 * precisionMultiplier )
404 floatMinutesY = std::max( floatMinutesY - 60, 0.0 );
412 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
423 if ( degreesY == 0 && std::round( floatMinutesY * precisionMultiplier ) == 0 )
431 QString strMinutesY = QString::fromStdWString( ss.str() );
432 ss.str( std::wstring() );
434 trimTrailingZeros( strMinutesY, context );
437 if ( mShowLeadingZeros && floatMinutesY < 10 )
438 strMinutesY =
'0' + strMinutesY;
440 ss << std::fixed << std::setprecision( 0 );
442 QString degreesYStr = QString::fromStdWString( ss.str() );
443 ss.str( std::wstring() );
445 if ( mShowLeadingDegreeZeros )
446 degreesYStr = QString( QStringLiteral(
"00" ) + degreesYStr ).right( 2 );
448 return sign + degreesYStr + QChar( 176 ) +
449 strMinutesY + QChar( 0x2032 ) +
453QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegreesMinutes(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
456 double wrappedX = std::fmod( val, 360.0 );
458 if ( wrappedX > 180.0 )
460 wrappedX = wrappedX - 360.0;
462 else if ( wrappedX < -180.0 )
464 wrappedX = wrappedX + 360.0;
467 int degreesX = int( std::fabs( wrappedX ) );
468 double floatMinutesX = ( std::fabs( wrappedX ) - degreesX ) * 60.0;
473 if ( std::round( floatMinutesX * precisionMultiplier ) >= 60 * precisionMultiplier )
475 floatMinutesX = std::max( floatMinutesX - 60, 0.0 );
483 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
494 if ( degreesX == 0 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
501 if ( degreesX == 180 && std::round( floatMinutesX * precisionMultiplier ) == 0 )
508 QString strMinutesX = QString::fromStdWString( ss.str() );
509 ss.str( std::wstring() );
511 trimTrailingZeros( strMinutesX, context );
514 if ( mShowLeadingZeros && floatMinutesX < 10 )
515 strMinutesX =
'0' + strMinutesX;
517 ss << std::fixed << std::setprecision( 0 );
519 QString degreesXStr = QString::fromStdWString( ss.str() );
520 ss.str( std::wstring() );
522 if ( mShowLeadingDegreeZeros )
523 degreesXStr = QString( QStringLiteral(
"000" ) + degreesXStr ).right( 3 );
525 return sign + degreesXStr + QChar( 176 ) +
526 strMinutesX + QChar( 0x2032 ) +
530QString QgsGeographicCoordinateNumericFormat::formatLatitudeAsDegrees(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
533 double wrappedY = std::fmod( val, 180.0 );
535 if ( wrappedY > 90.0 )
537 wrappedY = wrappedY - 180.0;
539 else if ( wrappedY < -90.0 )
541 wrappedY = wrappedY + 180.0;
544 const double absY = std::fabs( wrappedY );
552 hemisphere = wrappedY < 0 ? QObject::tr(
"S" ) : QObject::tr(
"N" );
563 if ( std::round( absY * precisionMultiplier ) == 0 )
571 QString strDegreesY = QString::fromStdWString( ss.str() );
572 ss.str( std::wstring() );
574 trimTrailingZeros( strDegreesY, context );
576 if ( mShowLeadingDegreeZeros && absY < 10 )
577 strDegreesY =
'0' + strDegreesY;
579 return sign + strDegreesY + QChar( 176 ) + hemisphere;
582QString QgsGeographicCoordinateNumericFormat::formatLongitudeAsDegrees(
double val, std::basic_stringstream<wchar_t> &ss,
const QgsNumericFormatContext &context )
const
585 double wrappedX = std::fmod( val, 360.0 );
587 if ( wrappedX > 180.0 )
589 wrappedX = wrappedX - 360.0;
591 else if ( wrappedX < -180.0 )
593 wrappedX = wrappedX + 360.0;
596 const double absX = std::fabs( wrappedX );
604 hemisphere = wrappedX < 0 ? QObject::tr(
"W" ) : QObject::tr(
"E" );
615 if ( std::round( absX * precisionMultiplier ) == 0 )
622 if ( std::round( absX * precisionMultiplier ) == 180 * precisionMultiplier )
630 QString strDegreesX = QString::fromStdWString( ss.str() );
631 ss.str( std::wstring() );
633 trimTrailingZeros( strDegreesX, context );
635 if ( mShowLeadingDegreeZeros && absX < 100 )
636 strDegreesX =
'0' + strDegreesX;
637 if ( mShowLeadingDegreeZeros && absX < 10 )
638 strDegreesX =
'0' + strDegreesX;
640 return sign + strDegreesX + QChar( 176 ) + hemisphere;
643void QgsGeographicCoordinateNumericFormat::trimTrailingZeros( QString &input,
const QgsNumericFormatContext &context )
const
648 int trimPoint = input.length() - 1;
650 while ( input.at( trimPoint ) == context.
zeroDigit() )
653 if ( input.at( trimPoint ) == decimal )
656 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.
The class is used as a container of context for various read/write operations on other 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