summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2021-07-29 11:34:16 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-07-29 11:28:07 +0000
commitade8147da038ebaae230a38a6e0f16364fc0edbe (patch)
tree1c7f3496eafb443bdd064e943591d7c0905ba527
parent89ababe4075f9e816ecd3c3e569fc6517d5e7244 (diff)
downloadqtlocation-ade8147da038ebaae230a38a6e0f16364fc0edbe.tar.gz
QGeoCoordinate: fix toString() conversion
Applying qRound() to check if the minutes/seconds should overflow was not the right solution in some cases. It could lead to incorrect overflows, and so - to wrong conversion results. The actual logic of overflow is related to the behavior of QString::number. This patch fixes the logic and also introduces some minor optimizations. After overflow, the minutes or seconds value is always 0.0, because the actual minutes/seconds value is always in range [0; 60). This allows us to get rid of some checks. Fixes: QTBUG-95221 Change-Id: Ie3dcb6cef226b04c43dd973c09c4ae297c583f3b Reviewed-by: Alex Blasche <alexander.blasche@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> (cherry picked from commit 15f06eca6a5085ce14d2eb0b743c5a06365068ea) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/positioning/qgeocoordinate.cpp47
-rw-r--r--tests/auto/qgeocoordinate/tst_qgeocoordinate.cpp20
2 files changed, 41 insertions, 26 deletions
diff --git a/src/positioning/qgeocoordinate.cpp b/src/positioning/qgeocoordinate.cpp
index fdc7ae4f..e0b1a0b3 100644
--- a/src/positioning/qgeocoordinate.cpp
+++ b/src/positioning/qgeocoordinate.cpp
@@ -594,19 +594,18 @@ QString QGeoCoordinate::toString(CoordinateFormat format) const
double latMin = (absLat - int(absLat)) * 60;
double lngMin = (absLng - int(absLng)) * 60;
- if (qRound(latMin) >= 60) {
+ // We use QString::number(val, 'f', 3) to represent minutes.
+ // It rounds up to the next integer in case the fraction > 0.9995.
+ // Such behavior should be handled specifically when the rounded
+ // value is 60, so that we overflow to degrees correctly.
+ // If we overflow, the minutes should unconditionally be 0.0.
+ if (latMin > 59.9995) {
absLat++;
- latMin = qAbs(latMin - 60.0f);
- //avoid invalid latitude due to latMin rounding below
- if (qRound(absLat) >= 90)
- latMin = 0.0f;
+ latMin = 0.0f;
}
- if (qRound(lngMin) >= 60) {
+ if (lngMin > 59.9995) {
absLng++;
- lngMin = qAbs(lngMin - 60.0f);
- // avoid invalid longitude due to lngMin rounding below
- if (qRound(absLng) >= 180)
- lngMin = 0.0f;
+ lngMin = 0.0f;
}
latStr = QString::fromLatin1("%1%2 %3'")
@@ -626,28 +625,28 @@ QString QGeoCoordinate::toString(CoordinateFormat format) const
double latSec = (latMin - int(latMin)) * 60;
double lngSec = (lngMin - int(lngMin)) * 60;
- // overflow to full minutes
- if (qRound(latSec) >= 60) {
+ // We use QString::number(val, 'f', 1) to represent seconds.
+ // It rounds up to the next integer in case the fraction >= 0.95.
+ // Such behavior should be handled specifically when the rounded
+ // value is 60, so that we overflow to minutes correctly.
+ // If we overflow, the seconds should unconditionally be 0.0.
+ if (latSec >= 59.95) {
latMin++;
- latSec = qAbs(latSec - 60.0f);
- // overflow to full degrees
+ latSec = 0.0f;
+ // We cast to int to represent minutes, so we can use qRound()
+ // to determine if we need to overflow to full degrees.
+ // If we overflow, the minutes will unconditionally be 0.0.
if (qRound(latMin) >= 60) {
absLat++;
- latMin = qAbs(latMin - 60.0f);
- // avoid invalid latitude due to latSec rounding below
- if (qRound(absLat) >= 90)
- latSec = 0.0f;
+ latMin = 0.0f;
}
}
- if (qRound(lngSec) >= 60) {
+ if (lngSec >= 59.95) {
lngMin++;
- lngSec = qAbs(lngSec - 60.0f);
+ lngSec = 0.0f;
if (qRound(lngMin) >= 60) {
absLng++;
- lngMin = qAbs(lngMin - 60.0f);
- // avoid invalid longitude due to lngSec rounding below
- if (qRound(absLng) >= 180)
- lngSec = 0.0f;
+ lngMin = 0.0f;
}
}
diff --git a/tests/auto/qgeocoordinate/tst_qgeocoordinate.cpp b/tests/auto/qgeocoordinate/tst_qgeocoordinate.cpp
index 1b30f647..28f10aca 100644
--- a/tests/auto/qgeocoordinate/tst_qgeocoordinate.cpp
+++ b/tests/auto/qgeocoordinate/tst_qgeocoordinate.cpp
@@ -843,13 +843,29 @@ private slots:
<< QString( "2%1 0.000', 2%1 0.000'").arg(DEGREES_SYMB);
QTest::newRow("Wrap seconds to minutes to Degrees DM -> above valid long/lat values")
- << QGeoCoordinate(89.9999, 179.9999) << QGeoCoordinate::DegreesMinutesSeconds
+ << QGeoCoordinate(89.999999, 179.999999) << QGeoCoordinate::DegreesMinutesSeconds
<< QString( "90%1 0' 0.0\", 180%1 0' 0.0\"").arg(DEGREES_SYMB);
+ QTest::newRow("Seconds and minutes near valid long/lat values border")
+ << QGeoCoordinate(89.9999, 179.9999) << QGeoCoordinate::DegreesMinutesSeconds
+ << QString("89%1 59' 59.6\", 179%1 59' 59.6\"").arg(DEGREES_SYMB);
+
QTest::newRow("Wrap minutes to Degrees DM ->above valid long/lat values")
- << QGeoCoordinate(89.9999, 179.9999) << QGeoCoordinate::DegreesMinutes
+ << QGeoCoordinate(89.999999, 179.999999) << QGeoCoordinate::DegreesMinutes
<< QString( "90%1 0.000', 180%1 0.000'").arg(DEGREES_SYMB);
+ QTest::newRow("Minutes near valid long/lat values border")
+ << QGeoCoordinate(89.9999, 179.9999) << QGeoCoordinate::DegreesMinutes
+ << QString("89%1 59.994', 179%1 59.994'").arg(DEGREES_SYMB);
+
+ QTest::newRow("Fix incorrect wrap minutes to degrees")
+ << QGeoCoordinate(0.995833, 0.995833) << QGeoCoordinate::DegreesMinutes
+ << QString("0%1 59.750', 0%1 59.750'").arg(DEGREES_SYMB);
+
+ QTest::newRow("Fix incorrect wrap seconds to minutes")
+ << QGeoCoordinate(0.9832222, 0.9832222) << QGeoCoordinate::DegreesMinutesSeconds
+ << QString("0%1 58' 59.6\", 0%1 58' 59.6\"").arg(DEGREES_SYMB);
+
}
void datastream()