summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Patrick Valsecchi <patrick@thus.ch>2015-02-23 13:38:41 +0100
committerGravatar Dirk Hohndel <dirk@hohndel.org>2015-02-23 05:37:34 -0800
commitce79b9ffa4062cc3976838cb9a5fedd31f2f3614 (patch)
tree8d5ab0a1af6ac06d23ba8e309aaeb121c7d4eac8
parent0f6f1c7ccf77d053db053f66fc3e41e016f1597b (diff)
downloadsubsurface-ce79b9ffa4062cc3976838cb9a5fedd31f2f3614.tar.gz
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>
-rw-r--r--qthelper.cpp66
-rw-r--r--tests/testgpscoords.cpp23
-rw-r--r--tests/testgpscoords.h4
3 files changed, 72 insertions, 21 deletions
diff --git a/qthelper.cpp b/qthelper.cpp
index b26bdf467..34aacaf70 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -71,6 +71,9 @@ extern "C" const char *printGPSCoords(int lat, int lon)
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,
const QString& negatives, const QString& others,
double& value)
@@ -92,7 +95,7 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
numberDefined = true;
posBeforeNumber = pos;
pos += numberRe.cap(1).size() - 1;
- } else if (positives.indexOf(txt[pos].toUpper()) >= 0) {
+ } else if (positives.indexOf(txt[pos]) >= 0) {
if (sign != 0)
return false;
sign = 1;
@@ -102,7 +105,7 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
++pos;
break;
}
- } else if (negatives.indexOf(txt[pos].toUpper()) >= 0) {
+ } else if (negatives.indexOf(txt[pos]) >= 0) {
if (sign != 0) {
if (others.indexOf(txt[pos]) >= 0)
//special case for the '-' sign => next coordinate
@@ -116,10 +119,11 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
++pos;
break;
}
- } else if (others.indexOf(txt[pos].toUpper()) >= 0) {
+ } else if (others.indexOf(txt[pos]) >= 0) {
//we are at the next coordinate.
break;
- } else if (DEGREE_SIGNS.indexOf(txt[pos]) >= 0) {
+ } else if (DEGREE_SIGNS.indexOf(txt[pos]) >= 0 ||
+ (txt[pos].isSpace() && !degreesDefined && numberDefined)) {
if (!numberDefined)
return false;
if (degreesDefined) {
@@ -131,20 +135,18 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
value += number;
numberDefined = false;
degreesDefined = true;
- } else if (txt[pos] == '\'') {
+ } else if (txt[pos] == '\'' || (txt[pos].isSpace() && !minutesDefined && numberDefined)) {
if (!numberDefined || minutesDefined)
return false;
value += number / 60.0;
numberDefined = false;
minutesDefined = true;
- } else if (txt[pos] == '"') {
+ } else if (txt[pos] == '"' || (txt[pos].isSpace() && !secondsDefined && numberDefined)) {
if (!numberDefined || secondsDefined)
return false;
value += number / 3600.0;
numberDefined = false;
secondsDefined = true;
- } else if (txt[pos] == ' ' || txt[pos] == '\t') {
- //ignore spaces
} else {
return false;
}
@@ -152,31 +154,53 @@ static bool parseCoord(const QString& txt, int& pos, const QString& positives,
}
if (!degreesDefined && numberDefined) {
value = number; //just a single number => degrees
- numberDefined = false;
- degreesDefined = true;
- }
- if (!degreesDefined || numberDefined)
+ } else if (!minutesDefined && numberDefined) {
+ value += number / 60.0;
+ } else if (!secondsDefined && numberDefined) {
+ value += number / 3600.0;
+ } else if (numberDefined) {
return false;
+ }
if (sign == -1) value *= -1.0;
return true;
}
+/**
+* Parse special coordinate formats that cannot be handled by parseCoord.
+*/
+static bool parseSpecialCoords(const QString& txt, double& latitude, double& longitude) {
+ QRegExp xmlFormat("(-?\\d+(?:\\.\\d+)?)\\s+(-?\\d+(?:\\.\\d+)?)");
+ if (xmlFormat.exactMatch(txt)) {
+ latitude = xmlFormat.cap(1).toDouble();
+ longitude = xmlFormat.cap(2).toDouble();
+ return true;
+ }
+ return false;
+}
+
bool parseGpsText(const QString &gps_text, double *latitude, double *longitude)
{
- const QString trimmed = gps_text.trimmed();
- if (trimmed.isEmpty()) {
+ static const QString POS_LAT = QString("+N") + translate("gettextFromC", "N");
+ static const QString NEG_LAT = QString("-S") + translate("gettextFromC", "S");
+ static const QString POS_LON = QString("+E") + translate("gettextFromC", "E");
+ static const QString NEG_LON = QString("-W") + translate("gettextFromC", "W");
+
+ //remove the useless spaces (but keep the ones separating numbers)
+ 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;
- static const QString POS_LAT = QString("+N") + translate("gettextFromC", "N");
- static const QString NEG_LAT = QString("-S") + translate("gettextFromC", "S");
- static const QString POS_LON = QString("+E") + translate("gettextFromC", "E");
- 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) &&
- pos == gps_text.size();
+ 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
diff --git a/tests/testgpscoords.cpp b/tests/testgpscoords.cpp
index a38dcc807..c5a4d22a4 100644
--- a/tests/testgpscoords.cpp
+++ b/tests/testgpscoords.cpp
@@ -77,6 +77,29 @@ void TestGpsCoords::testSpaceDecimalParse()
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,
double expectedLon)
diff --git a/tests/testgpscoords.h b/tests/testgpscoords.h
index 5add3da93..784bc302e 100644
--- a/tests/testgpscoords.h
+++ b/tests/testgpscoords.h
@@ -18,6 +18,10 @@ private slots:
void testDecimalParse();
void testSpaceDecimalParse();
void testDecimalInversedParse();
+ void testXmlFormatParse();
+ void testNoUnitParse();
+ void testNegativeXmlFormatParse();
+ void testPrefixNoUnitParse();
private:
static void testParseOK(const QString &txt, double expectedLat,