Lock map tracking to corrected IMU output
Ubuntu build / build-and-test (ubuntu-22.04) (push) Has been cancelled
Ubuntu build / build-and-test (ubuntu-24.04) (push) Has been cancelled

This commit is contained in:
2026-07-18 18:06:02 +03:00
parent 7a883b801f
commit f012b7a52a
5 changed files with 63 additions and 19 deletions
+8 -3
View File
@@ -465,9 +465,14 @@ void GlobeWidget::drawBlueMarble(QPainter &painter) const
}
const double radius = std::min(width(), height()) * 0.255 * m_zoom;
const double pixelRatio = std::min(devicePixelRatioF(), 2.0);
const int textureSize = std::clamp(
static_cast<int>(std::ceil(radius * 2.0 * pixelRatio)), 420, 1200);
// Interactive rotation favors latency; mouse release immediately causes
// a full Retina-quality rebuild. Satellite animation frames reuse the
// cached texture and therefore do not repeat this projection work.
const double pixelRatio = m_dragging ? std::min(devicePixelRatioF(), 1.0)
: std::min(devicePixelRatioF(), 2.0);
const int textureSize = m_dragging
? std::clamp(static_cast<int>(std::ceil(radius * 2.0 * pixelRatio)), 280, 650)
: std::clamp(static_cast<int>(std::ceil(radius * 2.0 * pixelRatio)), 420, 1200);
const QPointF center(width() * 0.5, height() * 0.52);
const QRectF target(center.x() - radius, center.y() - radius,
radius * 2.0, radius * 2.0);
+1
View File
@@ -164,6 +164,7 @@ LocationAnalysis analyzeLocations(const QVector<TelemetryPoint> &points)
QVector<TelemetryPoint> preferredAnalysisPoints(const QVector<TelemetryPoint> &points)
{
QVector<TelemetryPoint> corrected;
corrected.reserve(points.size());
for (const TelemetryPoint &point : points) {
if (point.source == LocationSource::ImuCorrected) {
corrected.push_back(point);
+30 -16
View File
@@ -91,9 +91,9 @@ void MapWidget::setPoints(const QVector<TelemetryPoint> &points)
m_points = points;
if (!m_points.isEmpty() && m_autoFollow) {
const TelemetryPoint &last = m_points.last();
m_centerLat = last.latitude;
m_centerLon = last.longitude;
const TelemetryPoint &focus = m_points[preferredFocusIndex()];
m_centerLat = focus.latitude;
m_centerLon = focus.longitude;
if (wasEmpty) {
m_zoom = MaxZoom;
}
@@ -232,9 +232,9 @@ void MapWidget::setAutoFollow(bool enabled)
m_autoFollow = enabled;
if (m_autoFollow && !m_points.isEmpty()) {
const TelemetryPoint &last = m_points.last();
m_centerLat = last.latitude;
m_centerLon = last.longitude;
const TelemetryPoint &focus = m_points[preferredFocusIndex()];
m_centerLat = focus.latitude;
m_centerLon = focus.longitude;
update();
}
emit autoFollowChanged(m_autoFollow);
@@ -522,9 +522,10 @@ void MapWidget::drawTelemetry(QPainter &painter)
drawCepMarker(painter);
const bool drawNumbers = m_points.size() <= 150;
const int firstPoint = m_showRecentPoints ? 0 : m_points.size() - 1;
for (int i = firstPoint; i < m_points.size(); ++i) {
const bool isLast = i == m_points.size() - 1;
const int focusIndex = preferredFocusIndex();
for (int i = 0; i < m_points.size(); ++i) {
if (!m_showRecentPoints && i != focusIndex) continue;
const bool isLast = i == focusIndex;
const QPointF screen = coordinateToScreen(m_points[i].latitude, m_points[i].longitude);
const double radius = isLast ? 8.0 : 5.0;
@@ -547,7 +548,7 @@ void MapWidget::drawTelemetry(QPainter &painter)
}
}
const TelemetryPoint &last = m_points.last();
const TelemetryPoint &last = m_points[focusIndex];
const QPointF lastScreen = coordinateToScreen(last.latitude, last.longitude);
QStringList lines;
const QString latitudeText = last.latitudeText.isEmpty()
@@ -655,9 +656,10 @@ void MapWidget::drawCepMarker(QPainter &painter)
painter.drawLine(QPointF(screen.x(), screen.y() - 11.0),
QPointF(screen.x(), screen.y() + 11.0));
const bool overlapsLast = !m_points.isEmpty()
&& QLineF(screen, coordinateToScreen(m_points.last().latitude,
m_points.last().longitude)).length() < 30.0;
const int focusIndex = preferredFocusIndex();
const bool overlapsLast = focusIndex >= 0
&& QLineF(screen, coordinateToScreen(m_points[focusIndex].latitude,
m_points[focusIndex].longitude)).length() < 30.0;
if (!overlapsLast) {
painter.setFont(QFont(painter.font().family(), 9, QFont::Bold));
painter.setPen(QColor(20, 83, 78));
@@ -691,9 +693,10 @@ void MapWidget::drawAverageOverlay(QPainter &painter)
painter.drawLine(QPointF(screen.x() - 12.0, screen.y()), QPointF(screen.x() + 12.0, screen.y()));
painter.drawLine(QPointF(screen.x(), screen.y() - 12.0), QPointF(screen.x(), screen.y() + 12.0));
const bool overlapsLast = !m_points.isEmpty()
&& QLineF(screen, coordinateToScreen(m_points.last().latitude,
m_points.last().longitude)).length() < 30.0;
const int focusIndex = preferredFocusIndex();
const bool overlapsLast = focusIndex >= 0
&& QLineF(screen, coordinateToScreen(m_points[focusIndex].latitude,
m_points[focusIndex].longitude)).length() < 30.0;
if (!overlapsLast) {
painter.setFont(QFont(painter.font().family(), 9, QFont::Bold));
const QRectF labelRect(screen + QPointF(12.0, 8.0), QSizeF(72.0, 20.0));
@@ -773,3 +776,14 @@ void MapWidget::disableAutoFollowFromUserAction()
m_autoFollow = false;
emit autoFollowChanged(false);
}
int MapWidget::preferredFocusIndex() const
{
// Once corrected ESKF output is present, both camera and detail bubble
// stay locked to its newest point. Raw GPS and truth records may arrive
// later in an interleaved stream and must not pull the camera away.
for (int index = m_points.size() - 1; index >= 0; --index) {
if (m_points[index].source == LocationSource::ImuCorrected) return index;
}
return m_points.isEmpty() ? -1 : m_points.size() - 1;
}
+2
View File
@@ -27,6 +27,7 @@ public:
void setCepMarker(double latitude, double longitude,
const std::optional<double> &radiusMeters);
void clearCepMarker();
[[nodiscard]] QPointF centerCoordinate() const { return {m_centerLat, m_centerLon}; }
public slots:
void setAutoFollow(bool enabled);
@@ -66,6 +67,7 @@ private:
void requestTile(int tileX, int tileY, int zoom);
void setZoomKeepingPoint(int newZoom, const QPointF &screenAnchor);
void disableAutoFollowFromUserAction();
int preferredFocusIndex() const;
QVector<TelemetryPoint> m_points;
QNetworkAccessManager *m_network = nullptr;
+22
View File
@@ -17,6 +17,7 @@
#include <QTemporaryFile>
#include <cassert>
#include <cmath>
namespace {
@@ -93,6 +94,27 @@ int main(int argc, char **argv)
assert(toggleSerialAction != nullptr && !toggleSerialAction->shortcut().isEmpty());
assert(rinexUpdateAction != nullptr && !rinexUpdateAction->shortcut().isEmpty());
QVector<TelemetryPoint> followPoints;
TelemetryPoint gpsPoint;
gpsPoint.source = LocationSource::Gps;
gpsPoint.latitude = 40.0;
gpsPoint.longitude = 29.0;
followPoints.push_back(gpsPoint);
TelemetryPoint correctedPoint = gpsPoint;
correctedPoint.source = LocationSource::ImuCorrected;
correctedPoint.latitude = 40.25;
correctedPoint.longitude = 29.5;
followPoints.push_back(correctedPoint);
TelemetryPoint trajectoryPoint = gpsPoint;
trajectoryPoint.source = LocationSource::Trajectory;
trajectoryPoint.latitude = 41.0;
trajectoryPoint.longitude = 30.0;
followPoints.push_back(trajectoryPoint);
map->setPoints(followPoints);
assert(std::abs(map->centerCoordinate().x() - 40.25) < 0.000001);
assert(std::abs(map->centerCoordinate().y() - 29.5) < 0.000001);
map->clearPoints();
assert(QMetaObject::invokeMethod(map, "referenceLocationSelected", Qt::DirectConnection,
Q_ARG(double, 40.25), Q_ARG(double, 29.5)));
assert(referenceLatInput->text() == QStringLiteral("40.250000000000000"));