mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Add support for more GPS coordinate formats.
As requested in the user forum and in the mailing list, now support: - 46.473881 6.784696 (format used in XML files) - 48 51.491n 2 17.677e I was not able to handle the XML format in a generic way without making the code too ugly. So I've added an exception. Signed-off-by: Patrick Valsecchi <patrick@thus.ch> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
0f6f1c7ccf
commit
ce79b9ffa4
3 changed files with 73 additions and 22 deletions
68
qthelper.cpp
68
qthelper.cpp
|
@ -71,6 +71,9 @@ extern "C" const char *printGPSCoords(int lat, int lon)
|
||||||
return strdup(result.toUtf8().data());
|
return strdup(result.toUtf8().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to parse in a generic manner a coordinate.
|
||||||
|
*/
|
||||||
static bool parseCoord(const QString& txt, int& pos, const QString& positives,
|
static bool parseCoord(const QString& txt, int& pos, const QString& positives,
|
||||||
const QString& negatives, const QString& others,
|
const QString& negatives, const QString& others,
|
||||||
double& value)
|
double& value)
|
||||||
|
@ -92,7 +95,7 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
|
||||||
numberDefined = true;
|
numberDefined = true;
|
||||||
posBeforeNumber = pos;
|
posBeforeNumber = pos;
|
||||||
pos += numberRe.cap(1).size() - 1;
|
pos += numberRe.cap(1).size() - 1;
|
||||||
} else if (positives.indexOf(txt[pos].toUpper()) >= 0) {
|
} else if (positives.indexOf(txt[pos]) >= 0) {
|
||||||
if (sign != 0)
|
if (sign != 0)
|
||||||
return false;
|
return false;
|
||||||
sign = 1;
|
sign = 1;
|
||||||
|
@ -102,7 +105,7 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
|
||||||
++pos;
|
++pos;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (negatives.indexOf(txt[pos].toUpper()) >= 0) {
|
} else if (negatives.indexOf(txt[pos]) >= 0) {
|
||||||
if (sign != 0) {
|
if (sign != 0) {
|
||||||
if (others.indexOf(txt[pos]) >= 0)
|
if (others.indexOf(txt[pos]) >= 0)
|
||||||
//special case for the '-' sign => next coordinate
|
//special case for the '-' sign => next coordinate
|
||||||
|
@ -116,10 +119,11 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
|
||||||
++pos;
|
++pos;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (others.indexOf(txt[pos].toUpper()) >= 0) {
|
} else if (others.indexOf(txt[pos]) >= 0) {
|
||||||
//we are at the next coordinate.
|
//we are at the next coordinate.
|
||||||
break;
|
break;
|
||||||
} else if (DEGREE_SIGNS.indexOf(txt[pos]) >= 0) {
|
} else if (DEGREE_SIGNS.indexOf(txt[pos]) >= 0 ||
|
||||||
|
(txt[pos].isSpace() && !degreesDefined && numberDefined)) {
|
||||||
if (!numberDefined)
|
if (!numberDefined)
|
||||||
return false;
|
return false;
|
||||||
if (degreesDefined) {
|
if (degreesDefined) {
|
||||||
|
@ -131,20 +135,18 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
|
||||||
value += number;
|
value += number;
|
||||||
numberDefined = false;
|
numberDefined = false;
|
||||||
degreesDefined = true;
|
degreesDefined = true;
|
||||||
} else if (txt[pos] == '\'') {
|
} else if (txt[pos] == '\'' || (txt[pos].isSpace() && !minutesDefined && numberDefined)) {
|
||||||
if (!numberDefined || minutesDefined)
|
if (!numberDefined || minutesDefined)
|
||||||
return false;
|
return false;
|
||||||
value += number / 60.0;
|
value += number / 60.0;
|
||||||
numberDefined = false;
|
numberDefined = false;
|
||||||
minutesDefined = true;
|
minutesDefined = true;
|
||||||
} else if (txt[pos] == '"') {
|
} else if (txt[pos] == '"' || (txt[pos].isSpace() && !secondsDefined && numberDefined)) {
|
||||||
if (!numberDefined || secondsDefined)
|
if (!numberDefined || secondsDefined)
|
||||||
return false;
|
return false;
|
||||||
value += number / 3600.0;
|
value += number / 3600.0;
|
||||||
numberDefined = false;
|
numberDefined = false;
|
||||||
secondsDefined = true;
|
secondsDefined = true;
|
||||||
} else if (txt[pos] == ' ' || txt[pos] == '\t') {
|
|
||||||
//ignore spaces
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -152,31 +154,53 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
|
||||||
}
|
}
|
||||||
if (!degreesDefined && numberDefined) {
|
if (!degreesDefined && numberDefined) {
|
||||||
value = number; //just a single number => degrees
|
value = number; //just a single number => degrees
|
||||||
numberDefined = false;
|
} else if (!minutesDefined && numberDefined) {
|
||||||
degreesDefined = true;
|
value += number / 60.0;
|
||||||
}
|
} else if (!secondsDefined && numberDefined) {
|
||||||
if (!degreesDefined || numberDefined)
|
value += number / 3600.0;
|
||||||
|
} else if (numberDefined) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (sign == -1) value *= -1.0;
|
if (sign == -1) value *= -1.0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseGpsText(const QString &gps_text, double *latitude, double *longitude)
|
/**
|
||||||
{
|
* Parse special coordinate formats that cannot be handled by parseCoord.
|
||||||
const QString trimmed = gps_text.trimmed();
|
*/
|
||||||
if (trimmed.isEmpty()) {
|
static bool parseSpecialCoords(const QString& txt, double& latitude, double& longitude) {
|
||||||
*latitude = 0.0;
|
QRegExp xmlFormat("(-?\\d+(?:\\.\\d+)?)\\s+(-?\\d+(?:\\.\\d+)?)");
|
||||||
*longitude = 0.0;
|
if (xmlFormat.exactMatch(txt)) {
|
||||||
|
latitude = xmlFormat.cap(1).toDouble();
|
||||||
|
longitude = xmlFormat.cap(2).toDouble();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
int pos = 0;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseGpsText(const QString &gps_text, double *latitude, double *longitude)
|
||||||
|
{
|
||||||
static const QString POS_LAT = QString("+N") + translate("gettextFromC", "N");
|
static const QString POS_LAT = QString("+N") + translate("gettextFromC", "N");
|
||||||
static const QString NEG_LAT = QString("-S") + translate("gettextFromC", "S");
|
static const QString NEG_LAT = QString("-S") + translate("gettextFromC", "S");
|
||||||
static const QString POS_LON = QString("+E") + translate("gettextFromC", "E");
|
static const QString POS_LON = QString("+E") + translate("gettextFromC", "E");
|
||||||
static const QString NEG_LON = QString("-W") + translate("gettextFromC", "W");
|
static const QString NEG_LON = QString("-W") + translate("gettextFromC", "W");
|
||||||
return parseCoord(gps_text, pos, POS_LAT, NEG_LAT, POS_LON + NEG_LON, *latitude) &&
|
|
||||||
parseCoord(gps_text, pos, POS_LON, NEG_LON, "", *longitude) &&
|
//remove the useless spaces (but keep the ones separating numbers)
|
||||||
pos == gps_text.size();
|
static const QRegExp SPACE_CLEANER("\\s*([" + POS_LAT + NEG_LAT + POS_LON +
|
||||||
|
NEG_LON + DEGREE_SIGNS + "'\"\\s])\\s*");
|
||||||
|
const QString normalized = gps_text.trimmed().toUpper().replace(SPACE_CLEANER, "\\1");
|
||||||
|
|
||||||
|
if (normalized.isEmpty()) {
|
||||||
|
*latitude = 0.0;
|
||||||
|
*longitude = 0.0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (parseSpecialCoords(normalized, *latitude, *longitude))
|
||||||
|
return true;
|
||||||
|
int pos = 0;
|
||||||
|
return parseCoord(normalized, pos, POS_LAT, NEG_LAT, POS_LON + NEG_LON, *latitude) &&
|
||||||
|
parseCoord(normalized, pos, POS_LON, NEG_LON, "", *longitude) &&
|
||||||
|
pos == normalized.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 // we'll need something like this for the dive site management, eventually
|
#if 0 // we'll need something like this for the dive site management, eventually
|
||||||
|
|
|
@ -77,6 +77,29 @@ void TestGpsCoords::testSpaceDecimalParse()
|
||||||
coord2double(52.83), coord2double(1.61));
|
coord2double(52.83), coord2double(1.61));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestGpsCoords::testXmlFormatParse()
|
||||||
|
{
|
||||||
|
testParseOK("46.473881 6.784696",
|
||||||
|
coord2double(46.473881), coord2double(6.784696));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestGpsCoords::testNegativeXmlFormatParse()
|
||||||
|
{
|
||||||
|
testParseOK("46.473881 -6.784696",
|
||||||
|
coord2double(46.473881), -coord2double(6.784696));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestGpsCoords::testNoUnitParse()
|
||||||
|
{
|
||||||
|
testParseOK("48 51.491n 2 17.677e",
|
||||||
|
coord2double(48, 51.491), coord2double(2, 17.677));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestGpsCoords::testPrefixNoUnitParse()
|
||||||
|
{
|
||||||
|
testParseOK("n48 51.491 w2 17.677",
|
||||||
|
coord2double(48, 51.491), -coord2double(2, 17.677));
|
||||||
|
}
|
||||||
|
|
||||||
void TestGpsCoords::testParseOK(const QString &txt, double expectedLat,
|
void TestGpsCoords::testParseOK(const QString &txt, double expectedLat,
|
||||||
double expectedLon)
|
double expectedLon)
|
||||||
|
|
|
@ -18,6 +18,10 @@ private slots:
|
||||||
void testDecimalParse();
|
void testDecimalParse();
|
||||||
void testSpaceDecimalParse();
|
void testSpaceDecimalParse();
|
||||||
void testDecimalInversedParse();
|
void testDecimalInversedParse();
|
||||||
|
void testXmlFormatParse();
|
||||||
|
void testNoUnitParse();
|
||||||
|
void testNegativeXmlFormatParse();
|
||||||
|
void testPrefixNoUnitParse();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void testParseOK(const QString &txt, double expectedLat,
|
static void testParseOK(const QString &txt, double expectedLat,
|
||||||
|
|
Loading…
Add table
Reference in a new issue