From 22c2971c3c0e8adaca544de78f78613fdc2231e7 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 24 Jun 2018 10:30:50 +0100 Subject: [PATCH] Lat-lon formatting: support nice degree symbols Allow Latin-1 (for PUI fnt) and UTF-8 (for Qt, osgText and everybody else) degree symbols as well as the use of * --- simgear/misc/strutils.cxx | 45 ++++++++++++++++++++++++---------- simgear/misc/strutils.hxx | 16 ++++++++++-- simgear/misc/strutils_test.cxx | 13 +++++++++- 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/simgear/misc/strutils.cxx b/simgear/misc/strutils.cxx index b0a75cbf..54b129d3 100644 --- a/simgear/misc/strutils.cxx +++ b/simgear/misc/strutils.cxx @@ -1196,12 +1196,24 @@ bool parseStringAsGeod(const std::string& s, SGGeod* result) return true; } -std::string formatLatLonValueAsString(double deg, LatLonFormat format, char c) +namespace { + const char* static_degreeSymbols[] = { + "*", + " ", + "\xB0", // Latin-1 B0 codepoint + "\xC2\xB0" // UTF-8 equivalent + }; +} // of anonymous namespace + +std::string formatLatLonValueAsString(double deg, LatLonFormat format, + char c, + DegreeSymbol degreeSymbol) { double min, sec; const int sign = deg < 0.0 ? -1 : 1; deg = fabs(deg); char buf[128]; + const char* degSym = static_degreeSymbols[static_cast(degreeSymbol)]; switch (format) { case LatLonFormat::DECIMAL_DEGREES: @@ -1217,7 +1229,7 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format, char c) min -= 60.0; deg += 1.0; } - snprintf(buf, sizeof(buf), "%d*%06.3f'%c", int(deg), fabs(min), c); + snprintf(buf, sizeof(buf), "%d%s%06.3f'%c", int(deg), degSym, fabs(min), c); break; case LatLonFormat::DEGREES_MINUTES_SECONDS: @@ -1234,7 +1246,8 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format, char c) deg += 1.0; } } - ::snprintf(buf, sizeof(buf), "%d*%02d'%04.1f\"%c", int(deg), int(min), fabs(sec), c); + ::snprintf(buf, sizeof(buf), "%d%s%02d'%04.1f\"%c", int(deg), degSym, + int(min), fabs(sec), c); break; case LatLonFormat::SIGNED_DECIMAL_DEGREES: @@ -1250,9 +1263,9 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format, char c) deg += 1.0; } if (sign == 1) { - snprintf(buf, sizeof(buf), "%d*%06.3f'", int(deg), fabs(min)); + snprintf(buf, sizeof(buf), "%d%s%06.3f'", int(deg), degSym, fabs(min)); } else { - snprintf(buf, sizeof(buf), "-%d*%06.3f'", int(deg), fabs(min)); + snprintf(buf, sizeof(buf), "-%d%s%06.3f'", int(deg), degSym, fabs(min)); } break; @@ -1270,9 +1283,9 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format, char c) } } if (sign == 1) { - snprintf(buf, sizeof(buf), "%d*%02d'%04.1f\"", int(deg), int(min), fabs(sec)); + snprintf(buf, sizeof(buf), "%d%s%02d'%04.1f\"", int(deg), degSym, int(min), fabs(sec)); } else { - snprintf(buf, sizeof(buf), "-%d*%02d'%04.1f\"", int(deg), int(min), fabs(sec)); + snprintf(buf, sizeof(buf), "-%d%s%02d'%04.1f\"", int(deg), degSym, int(min), fabs(sec)); } break; @@ -1293,9 +1306,9 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format, char c) deg += 1.0; } if (c == 'N' || c == 'S') { - snprintf(buf, sizeof(buf), "%02d*%06.3f'%c", int(deg), fabs(min), c); + snprintf(buf, sizeof(buf), "%02d%s%06.3f'%c", int(deg), degSym, fabs(min), c); } else { - snprintf(buf, sizeof(buf), "%03d*%06.3f'%c", int(deg), fabs(min), c); + snprintf(buf, sizeof(buf), "%03d%s%06.3f'%c", int(deg), degSym, fabs(min), c); } break; @@ -1312,9 +1325,9 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format, char c) } } if (c == 'N' || c == 'S') { - snprintf(buf, sizeof(buf), "%02d*%02d'%04.1f\"%c", int(deg), int(min), fabs(sec), c); + snprintf(buf, sizeof(buf), "%02d%s%02d'%04.1f\"%c", int(deg), degSym, int(min), fabs(sec), c); } else { - snprintf(buf, sizeof(buf), "%03d*%02d'%04.1f\"%c", int(deg), int(min), fabs(sec), c); + snprintf(buf, sizeof(buf), "%03d%s%02d'%04.1f\"%c", int(deg), degSym, int(min), fabs(sec), c); } break; @@ -1331,17 +1344,23 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format, char c) snprintf(buf, sizeof(buf), "%03d* %02d'.%03d%c", int(deg), int(min), int(SGMisc::round((min-int(min))*1000)), c); } break; + + case LatLonFormat::DECIMAL_DEGREES_SYMBOL: + ::snprintf(buf, sizeof(buf), "%3.6f%s%c", deg, degSym, c); + break; } return std::string(buf); } -std::string formatGeodAsString(const SGGeod& geod, LatLonFormat format) +std::string formatGeodAsString(const SGGeod& geod, LatLonFormat format, + DegreeSymbol degreeSymbol) { const char ns = (geod.getLatitudeDeg() > 0.0) ? 'N' : 'S'; const char ew = (geod.getLongitudeDeg() > 0.0) ? 'E' : 'W'; - return formatLatLonValueAsString(geod.getLatitudeDeg(), format, ns) + "," + formatLatLonValueAsString(geod.getLongitudeDeg(), format, ew); + return formatLatLonValueAsString(geod.getLatitudeDeg(), format, ns, degreeSymbol) + "," + + formatLatLonValueAsString(geod.getLongitudeDeg(), format, ew, degreeSymbol); } } // end namespace strutils diff --git a/simgear/misc/strutils.hxx b/simgear/misc/strutils.hxx index e17244fe..cc735982 100644 --- a/simgear/misc/strutils.hxx +++ b/simgear/misc/strutils.hxx @@ -385,16 +385,28 @@ namespace simgear { ZERO_PAD_DEGREES_MINUTES, ZERO_PAD_DEGREES_MINUTES_SECONDS, TRINITY_HOUSE, ///< dd* mm'.mmm X, ddd* mm'.mmm X (Trinity House Navigation standard). + DECIMAL_DEGREES_SYMBOL ///< 88.4*N,4.54*W }; - std::string formatLatLonValueAsString(double deg, LatLonFormat format, char c); + enum class DegreeSymbol + { + ASTERISK = 0, + SPACE, + LATIN1_DEGREE, + UTF8_DEGREE + }; + + std::string formatLatLonValueAsString(double deg, + LatLonFormat format, char c, + DegreeSymbol degreeSymbol = DegreeSymbol::ASTERISK); /** * Format an SGGeod as a string according to the provided rule. * if the SGGeod is invalid (default constructed), will return an empty string */ std::string formatGeodAsString(const SGGeod& geod, - LatLonFormat format = LatLonFormat::DECIMAL_DEGREES); + LatLonFormat format = LatLonFormat::DECIMAL_DEGREES, + DegreeSymbol degreeSymbol = DegreeSymbol::ASTERISK); } // end namespace strutils } // end namespace simgear diff --git a/simgear/misc/strutils_test.cxx b/simgear/misc/strutils_test.cxx index c7c13dd2..8d17e0ed 100644 --- a/simgear/misc/strutils_test.cxx +++ b/simgear/misc/strutils_test.cxx @@ -647,7 +647,18 @@ void test_formatGeod() SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::SIGNED_DECIMAL_DEGREES), "55.450000,-3.460000"); SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::DEGREES_MINUTES_SECONDS), "55*27'00.0\"N,3*27'36.0\"W"); - + + const auto s = strutils::formatGeodAsString(a, + strutils::LatLonFormat::ZERO_PAD_DEGREES_MINUTES, + strutils::DegreeSymbol::LATIN1_DEGREE); + SG_CHECK_EQUAL(s, "55\xB0" "27.000'N,003\xB0" "27.600'W"); + + // Jakarta, if you care + SGGeod b = SGGeod::fromDeg(106.8278, -6.1568); + const auto s2 = strutils::formatGeodAsString(b, + strutils::LatLonFormat::DECIMAL_DEGREES_SYMBOL, + strutils::DegreeSymbol::UTF8_DEGREE); + SG_CHECK_EQUAL(s2, "6.156800\xC2\xB0S,106.827800\xC2\xB0" "E"); } int main(int argc, char* argv[])