Lat-lon parsing: allow lon,lat order, and detect order
Flightplan/route-manager defaults to lon,lat order. Allow the parser to detect the correct order when NSEW suffixes are provided and consistent.
This commit is contained in:
parent
609ac93c10
commit
d7a413d5e7
@ -1179,7 +1179,21 @@ bool parseStringAsLatLonValue(const std::string& s, double& degrees)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parseStringAsGeod(const std::string& s, SGGeod* result)
|
||||
namespace {
|
||||
bool isLatString(const std::string &s)
|
||||
{
|
||||
const char lastChar = ::toupper(s.back());
|
||||
return (lastChar == 'N') || (lastChar == 'S');
|
||||
}
|
||||
|
||||
bool isLonString(const std::string &s)
|
||||
{
|
||||
const char lastChar = ::toupper(s.back());
|
||||
return (lastChar == 'E') || (lastChar == 'W');
|
||||
}
|
||||
} // of anonymous namespace
|
||||
|
||||
bool parseStringAsGeod(const std::string& s, SGGeod* result, bool assumeLonLatOrder)
|
||||
{
|
||||
if (s.empty())
|
||||
return false;
|
||||
@ -1189,16 +1203,27 @@ bool parseStringAsGeod(const std::string& s, SGGeod* result)
|
||||
return false;
|
||||
}
|
||||
|
||||
double lat, lon;
|
||||
if (!parseStringAsLatLonValue(s.substr(0, commaPos), lat) ||
|
||||
!parseStringAsLatLonValue(s.substr(commaPos+1), lon))
|
||||
{
|
||||
auto termA = simplify(s.substr(0, commaPos)),
|
||||
termB = simplify(s.substr(commaPos+1));
|
||||
double valueA, valueB;
|
||||
if (!parseStringAsLatLonValue(termA, valueA) || !parseStringAsLatLonValue(termB, valueB)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
*result = SGGeod::fromDeg(lon, lat);
|
||||
// explicit ordering
|
||||
if (isLatString(termA) && isLonString(termB)) {
|
||||
*result = SGGeod::fromDeg(valueB, valueA);
|
||||
} else if (isLonString(termA) && isLatString(termB)) {
|
||||
*result = SGGeod::fromDeg(valueA, valueB);
|
||||
} else {
|
||||
// implicit ordering
|
||||
// SGGeod wants longitude, latitude
|
||||
*result = assumeLonLatOrder ? SGGeod::fromDeg(valueA, valueB)
|
||||
: SGGeod::fromDeg(valueB, valueA);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -367,8 +367,19 @@ namespace simgear {
|
||||
*
|
||||
* Supported formats:
|
||||
* <signed decimal degrees latitude>,<signed decimal degress longitude>
|
||||
* <unsigned decimal degrees>[NS],<unsigned decimal degrees>[EW]
|
||||
* <degrees>*<decimal minutes>'[NS],<degrees>*<decimal minutes>'[EW]
|
||||
*
|
||||
* Latitude and longitude are parsed seperately so the formats for each
|
||||
* do not need to agree. Latitude is assumed to precede longitude
|
||||
* unless assumeLonLatOrder = true
|
||||
*
|
||||
* When NSEW characters are used, the order can be swapped and will be
|
||||
* fixed correctly (longitude then latitude).
|
||||
*/
|
||||
bool parseStringAsGeod(const std::string& string, SGGeod* result = nullptr);
|
||||
bool parseStringAsGeod(const std::string& string,
|
||||
SGGeod* result = nullptr,
|
||||
bool assumeLonLatOrder = false);
|
||||
|
||||
// enum values here correspond to existing lon-lat format codes inside
|
||||
// FlightGear (property: /sim/lon-lat-format )
|
||||
|
@ -654,6 +654,28 @@ void test_parseGeod()
|
||||
|
||||
SG_VERIFY(strutils::parseStringAsGeod("") == false);
|
||||
SG_VERIFY(strutils::parseStringAsGeod("aaaaaaaa") == false);
|
||||
|
||||
// ordering tests
|
||||
|
||||
// normal default order, but explicitly pass as lon,lat
|
||||
// (should work)
|
||||
SG_VERIFY(strutils::parseStringAsGeod("3.12345678w, 56.12345678s", &a));
|
||||
SG_CHECK_EQUAL_EP(a.getLongitudeDeg(), -3.12345678);
|
||||
SG_CHECK_EQUAL_EP(a.getLatitudeDeg(), -56.12345678);
|
||||
|
||||
|
||||
// different default order
|
||||
// also some embedded whitespace for fun
|
||||
SG_VERIFY(strutils::parseStringAsGeod(" -12 34.56,\n-45 27.89 ", &a, true));
|
||||
SG_CHECK_EQUAL_EP(a.getLongitudeDeg(), -12.576);
|
||||
SG_CHECK_EQUAL_EP(a.getLatitudeDeg(), -45.464833333);
|
||||
|
||||
|
||||
// differnet default order, but still set explicitly so should
|
||||
// use the lat,lon order
|
||||
SG_VERIFY(strutils::parseStringAsGeod("\t40 30'50\"S, 12 34'56\"W ", &a, true));
|
||||
SG_CHECK_EQUAL_EP(a.getLongitudeDeg(), -12.58222222);
|
||||
SG_CHECK_EQUAL_EP(a.getLatitudeDeg(), -40.5138888);
|
||||
}
|
||||
|
||||
void test_formatGeod()
|
||||
|
Loading…
Reference in New Issue
Block a user