Merge GUI updates into macOS branch
Ubuntu build / build-and-test (ubuntu-22.04) (push) Has been cancelled
Ubuntu build / build-and-test (ubuntu-24.04) (push) Has been cancelled

# Conflicts:
#	src/GlobeWidget.cpp
#	src/GlobeWidget.h
#	src/MainWindow.h
#	src/MapWidget.cpp
#	src/MapWidget.h
#	src/RinexNavigation.cpp
This commit is contained in:
2026-07-24 00:14:47 +03:00
14 changed files with 672 additions and 329 deletions
+36
View File
@@ -1,4 +1,5 @@
#include "../src/MainWindow.h"
#include "../src/GlobeWidget.h"
#include "../src/MapWidget.h"
#include <QApplication>
@@ -54,6 +55,8 @@ int main(int argc, char **argv)
auto *showRecentPoints = window.findChild<QCheckBox *>(QStringLiteral("showRecentPointsCheck"));
auto *showAverage = window.findChild<QCheckBox *>(QStringLiteral("showAverageCheck"));
auto *portSelector = window.findChild<QComboBox *>(QStringLiteral("portSelector"));
auto *refreshRinexButton =
window.findChild<QPushButton *>(QStringLiteral("refreshRinexButton"));
auto *map = window.findChild<MapWidget *>();
auto *mainViewTabs = window.findChild<QTabWidget *>(QStringLiteral("mainViewTabs"));
auto *sideSplitter = window.findChild<QSplitter *>(QStringLiteral("sideSplitter"));
@@ -76,6 +79,9 @@ int main(int argc, char **argv)
assert(showRecentPoints != nullptr);
assert(showAverage != nullptr);
assert(portSelector != nullptr);
assert(refreshRinexButton != nullptr);
assert(refreshRinexButton->text() == QStringLiteral("RINEX Guncelle")
|| refreshRinexButton->text() == QStringLiteral("RINEX indiriliyor..."));
assert(portSelector->isEditable());
assert(portSelector->count() >= 1);
assert(portSelector->currentText() == QStringLiteral("/dev/test-usb-uart"));
@@ -115,6 +121,15 @@ int main(int argc, char **argv)
assert(std::abs(map->centerCoordinate().y() - 29.5) < 0.000001);
map->clearPoints();
sendLine(window, QStringLiteral("[TRK] tracked satellites=2 prns=[3,8]"));
assert(map != nullptr);
auto *globe = window.findChild<GlobeWidget *>();
assert(globe != nullptr);
assert(globe->observedPrns()
== QSet<QString>({QStringLiteral("G03"), QStringLiteral("G08")}));
sendLine(window, QStringLiteral("[TRK] tracked satellites=1 prns=[14]"));
assert(globe->observedPrns() == QSet<QString>({QStringLiteral("G14")}));
assert(QMetaObject::invokeMethod(map, "referenceLocationSelected", Qt::DirectConnection,
Q_ARG(double, 40.25), Q_ARG(double, 29.5)));
assert(referenceLatInput->text() == QStringLiteral("40.250000000000000"));
@@ -236,6 +251,27 @@ int main(int argc, char **argv)
assert(QMetaObject::invokeMethod(&window, "clearPoints", Qt::DirectConnection));
maxPointsInput->setValue(10);
{
MapWidget followMap;
TelemetryPoint corrected;
corrected.source = LocationSource::ImuCorrected;
corrected.latitude = 40.1;
corrected.longitude = 29.1;
corrected.receivedAt = QDateTime::currentDateTimeUtc();
TelemetryPoint rawGps;
rawGps.source = LocationSource::Gps;
rawGps.latitude = 41.0;
rawGps.longitude = 30.0;
rawGps.receivedAt = corrected.receivedAt.addMSecs(100);
followMap.setPoints({corrected, rawGps});
assert(followMap.centerCoordinate() == QPointF(40.1, 29.1));
rawGps.receivedAt = corrected.receivedAt.addMSecs(1100);
followMap.setPoints({corrected, rawGps});
assert(followMap.centerCoordinate() == QPointF(41.0, 30.0));
}
const QByteArray screenshotPath = qgetenv("LOCATION_PLOTTER_TEST_SCREENSHOT");
if (!screenshotPath.isEmpty()) {
sendLine(window, QStringLiteral("NAV solve start sats:5"));
+55 -3
View File
@@ -9,9 +9,39 @@
namespace {
bool closeTo(double left, double right)
bool closeTo(double left, double right, double tolerance = 0.000001)
{
return std::fabs(left - right) < 0.000001;
return std::fabs(left - right) < tolerance;
}
QString rinexField(double value)
{
return QStringLiteral("%1").arg(value, 19, 'E', 12);
}
QString rinexContinuation(std::initializer_list<double> values)
{
QString line(4, QLatin1Char(' '));
for (double value : values) line += rinexField(value);
return line + QLatin1Char('\n');
}
QByteArray syntheticGpsNavigation(const QDateTime &gpsEpochLabel, int gpsWeek, double toe)
{
QString rinex = QStringLiteral(
" 3.05 N: GNSS NAV DATA M: MIXED RINEX VERSION / TYPE\n"
" END OF HEADER\n");
rinex += QStringLiteral("G01 %1").arg(
gpsEpochLabel.toString(QStringLiteral("yyyy MM dd HH mm ss")));
rinex += rinexField(0.0) + rinexField(0.0) + rinexField(0.0) + QLatin1Char('\n');
rinex += rinexContinuation({1.0, 0.0, 0.0, 0.0});
rinex += rinexContinuation({0.0, 0.0, 0.0, 5153.7954775});
rinex += rinexContinuation({toe, 0.0, 0.0, 0.0});
rinex += rinexContinuation({0.0, 0.0, 0.0, 0.0});
rinex += rinexContinuation({0.0, 0.0, static_cast<double>(gpsWeek), 0.0});
rinex += rinexContinuation({2.0, 0.0, 0.0, 1.0});
rinex += rinexContinuation({0.0, 0.0, 0.0, 0.0});
return rinex.toLatin1();
}
} // namespace
@@ -181,11 +211,14 @@ int main(int argc, char **argv)
{
const auto parsed = LocationParser::parseLine(QStringLiteral(
"[LOCATION] source=imu_corrected lat=40.7356 lon=31.5985 height=812.7 "
"[LOCATION] source=imu_corrected mode=dead_reckoning "
"lat=40.7356 lon=31.5985 height=812.7 gps_age_ms=3180 "
"gdop=4.7 pdop=4.1 hdop=2.7 vdop=3.0 tdop=2.3 tracked=6 used=5"));
assert(parsed.has_value());
assert(parsed->hasLocation());
assert(parsed->source == LocationSource::ImuCorrected);
assert(parsed->fusionMode == FusionMode::DeadReckoning);
assert(parsed->gpsAgeMs == 3180);
assert(parsed->satellites == 6);
assert(closeTo(*parsed->dop.hdop, 2.7));
}
@@ -207,6 +240,25 @@ int main(int argc, char **argv)
assert(parsed->satellites == 4);
}
{
constexpr int gpsWeek = 2428;
constexpr double toe = 403200.0;
const QDateTime gpsEpoch(QDate(1980, 1, 6), QTime(0, 0), Qt::UTC);
const QDateTime gpsLabel = gpsEpoch.addSecs(
static_cast<qint64>(gpsWeek * 604800.0 + toe));
const QDateTime matchingUtc = gpsLabel.addSecs(-18);
QString error;
const auto satellites = RinexNavigation::parseGpsNavigation(
syntheticGpsNavigation(gpsLabel, gpsWeek, toe), matchingUtc, &error);
assert(error.isEmpty());
assert(satellites.size() == 1);
const double semiMajorAxis = 5153.7954775 * 5153.7954775;
const double node = -7.2921151467e-5 * toe;
assert(closeTo(satellites[0].x, semiMajorAxis * std::cos(node), 0.1));
assert(closeTo(satellites[0].y, semiMajorAxis * std::sin(node), 0.1));
assert(closeTo(satellites[0].z, 0.0, 0.1));
}
const QString rinexPath = qEnvironmentVariable("LOCATION_PLOTTER_TEST_RINEX");
if (!rinexPath.isEmpty()) {
QFile file(rinexPath);