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 *
This commit is contained in:
James Turner 2018-06-24 10:30:50 +01:00
parent 05e3c29ee4
commit 22c2971c3c
3 changed files with 58 additions and 16 deletions

View File

@ -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<int>(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<double>::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

View File

@ -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

View File

@ -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[])