Lock map tracking to corrected IMU output
This commit is contained in:
+8
-3
@@ -465,9 +465,14 @@ void GlobeWidget::drawBlueMarble(QPainter &painter) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const double radius = std::min(width(), height()) * 0.255 * m_zoom;
|
const double radius = std::min(width(), height()) * 0.255 * m_zoom;
|
||||||
const double pixelRatio = std::min(devicePixelRatioF(), 2.0);
|
// Interactive rotation favors latency; mouse release immediately causes
|
||||||
const int textureSize = std::clamp(
|
// a full Retina-quality rebuild. Satellite animation frames reuse the
|
||||||
static_cast<int>(std::ceil(radius * 2.0 * pixelRatio)), 420, 1200);
|
// 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 QPointF center(width() * 0.5, height() * 0.52);
|
||||||
const QRectF target(center.x() - radius, center.y() - radius,
|
const QRectF target(center.x() - radius, center.y() - radius,
|
||||||
radius * 2.0, radius * 2.0);
|
radius * 2.0, radius * 2.0);
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ LocationAnalysis analyzeLocations(const QVector<TelemetryPoint> &points)
|
|||||||
QVector<TelemetryPoint> preferredAnalysisPoints(const QVector<TelemetryPoint> &points)
|
QVector<TelemetryPoint> preferredAnalysisPoints(const QVector<TelemetryPoint> &points)
|
||||||
{
|
{
|
||||||
QVector<TelemetryPoint> corrected;
|
QVector<TelemetryPoint> corrected;
|
||||||
|
corrected.reserve(points.size());
|
||||||
for (const TelemetryPoint &point : points) {
|
for (const TelemetryPoint &point : points) {
|
||||||
if (point.source == LocationSource::ImuCorrected) {
|
if (point.source == LocationSource::ImuCorrected) {
|
||||||
corrected.push_back(point);
|
corrected.push_back(point);
|
||||||
|
|||||||
+30
-16
@@ -91,9 +91,9 @@ void MapWidget::setPoints(const QVector<TelemetryPoint> &points)
|
|||||||
m_points = points;
|
m_points = points;
|
||||||
|
|
||||||
if (!m_points.isEmpty() && m_autoFollow) {
|
if (!m_points.isEmpty() && m_autoFollow) {
|
||||||
const TelemetryPoint &last = m_points.last();
|
const TelemetryPoint &focus = m_points[preferredFocusIndex()];
|
||||||
m_centerLat = last.latitude;
|
m_centerLat = focus.latitude;
|
||||||
m_centerLon = last.longitude;
|
m_centerLon = focus.longitude;
|
||||||
if (wasEmpty) {
|
if (wasEmpty) {
|
||||||
m_zoom = MaxZoom;
|
m_zoom = MaxZoom;
|
||||||
}
|
}
|
||||||
@@ -232,9 +232,9 @@ void MapWidget::setAutoFollow(bool enabled)
|
|||||||
|
|
||||||
m_autoFollow = enabled;
|
m_autoFollow = enabled;
|
||||||
if (m_autoFollow && !m_points.isEmpty()) {
|
if (m_autoFollow && !m_points.isEmpty()) {
|
||||||
const TelemetryPoint &last = m_points.last();
|
const TelemetryPoint &focus = m_points[preferredFocusIndex()];
|
||||||
m_centerLat = last.latitude;
|
m_centerLat = focus.latitude;
|
||||||
m_centerLon = last.longitude;
|
m_centerLon = focus.longitude;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
emit autoFollowChanged(m_autoFollow);
|
emit autoFollowChanged(m_autoFollow);
|
||||||
@@ -522,9 +522,10 @@ void MapWidget::drawTelemetry(QPainter &painter)
|
|||||||
drawCepMarker(painter);
|
drawCepMarker(painter);
|
||||||
|
|
||||||
const bool drawNumbers = m_points.size() <= 150;
|
const bool drawNumbers = m_points.size() <= 150;
|
||||||
const int firstPoint = m_showRecentPoints ? 0 : m_points.size() - 1;
|
const int focusIndex = preferredFocusIndex();
|
||||||
for (int i = firstPoint; i < m_points.size(); ++i) {
|
for (int i = 0; i < m_points.size(); ++i) {
|
||||||
const bool isLast = i == m_points.size() - 1;
|
if (!m_showRecentPoints && i != focusIndex) continue;
|
||||||
|
const bool isLast = i == focusIndex;
|
||||||
const QPointF screen = coordinateToScreen(m_points[i].latitude, m_points[i].longitude);
|
const QPointF screen = coordinateToScreen(m_points[i].latitude, m_points[i].longitude);
|
||||||
const double radius = isLast ? 8.0 : 5.0;
|
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);
|
const QPointF lastScreen = coordinateToScreen(last.latitude, last.longitude);
|
||||||
QStringList lines;
|
QStringList lines;
|
||||||
const QString latitudeText = last.latitudeText.isEmpty()
|
const QString latitudeText = last.latitudeText.isEmpty()
|
||||||
@@ -655,9 +656,10 @@ void MapWidget::drawCepMarker(QPainter &painter)
|
|||||||
painter.drawLine(QPointF(screen.x(), screen.y() - 11.0),
|
painter.drawLine(QPointF(screen.x(), screen.y() - 11.0),
|
||||||
QPointF(screen.x(), screen.y() + 11.0));
|
QPointF(screen.x(), screen.y() + 11.0));
|
||||||
|
|
||||||
const bool overlapsLast = !m_points.isEmpty()
|
const int focusIndex = preferredFocusIndex();
|
||||||
&& QLineF(screen, coordinateToScreen(m_points.last().latitude,
|
const bool overlapsLast = focusIndex >= 0
|
||||||
m_points.last().longitude)).length() < 30.0;
|
&& QLineF(screen, coordinateToScreen(m_points[focusIndex].latitude,
|
||||||
|
m_points[focusIndex].longitude)).length() < 30.0;
|
||||||
if (!overlapsLast) {
|
if (!overlapsLast) {
|
||||||
painter.setFont(QFont(painter.font().family(), 9, QFont::Bold));
|
painter.setFont(QFont(painter.font().family(), 9, QFont::Bold));
|
||||||
painter.setPen(QColor(20, 83, 78));
|
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() - 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));
|
painter.drawLine(QPointF(screen.x(), screen.y() - 12.0), QPointF(screen.x(), screen.y() + 12.0));
|
||||||
|
|
||||||
const bool overlapsLast = !m_points.isEmpty()
|
const int focusIndex = preferredFocusIndex();
|
||||||
&& QLineF(screen, coordinateToScreen(m_points.last().latitude,
|
const bool overlapsLast = focusIndex >= 0
|
||||||
m_points.last().longitude)).length() < 30.0;
|
&& QLineF(screen, coordinateToScreen(m_points[focusIndex].latitude,
|
||||||
|
m_points[focusIndex].longitude)).length() < 30.0;
|
||||||
if (!overlapsLast) {
|
if (!overlapsLast) {
|
||||||
painter.setFont(QFont(painter.font().family(), 9, QFont::Bold));
|
painter.setFont(QFont(painter.font().family(), 9, QFont::Bold));
|
||||||
const QRectF labelRect(screen + QPointF(12.0, 8.0), QSizeF(72.0, 20.0));
|
const QRectF labelRect(screen + QPointF(12.0, 8.0), QSizeF(72.0, 20.0));
|
||||||
@@ -773,3 +776,14 @@ void MapWidget::disableAutoFollowFromUserAction()
|
|||||||
m_autoFollow = false;
|
m_autoFollow = false;
|
||||||
emit autoFollowChanged(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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
void setCepMarker(double latitude, double longitude,
|
void setCepMarker(double latitude, double longitude,
|
||||||
const std::optional<double> &radiusMeters);
|
const std::optional<double> &radiusMeters);
|
||||||
void clearCepMarker();
|
void clearCepMarker();
|
||||||
|
[[nodiscard]] QPointF centerCoordinate() const { return {m_centerLat, m_centerLon}; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setAutoFollow(bool enabled);
|
void setAutoFollow(bool enabled);
|
||||||
@@ -66,6 +67,7 @@ private:
|
|||||||
void requestTile(int tileX, int tileY, int zoom);
|
void requestTile(int tileX, int tileY, int zoom);
|
||||||
void setZoomKeepingPoint(int newZoom, const QPointF &screenAnchor);
|
void setZoomKeepingPoint(int newZoom, const QPointF &screenAnchor);
|
||||||
void disableAutoFollowFromUserAction();
|
void disableAutoFollowFromUserAction();
|
||||||
|
int preferredFocusIndex() const;
|
||||||
|
|
||||||
QVector<TelemetryPoint> m_points;
|
QVector<TelemetryPoint> m_points;
|
||||||
QNetworkAccessManager *m_network = nullptr;
|
QNetworkAccessManager *m_network = nullptr;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -93,6 +94,27 @@ int main(int argc, char **argv)
|
|||||||
assert(toggleSerialAction != nullptr && !toggleSerialAction->shortcut().isEmpty());
|
assert(toggleSerialAction != nullptr && !toggleSerialAction->shortcut().isEmpty());
|
||||||
assert(rinexUpdateAction != nullptr && !rinexUpdateAction->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,
|
assert(QMetaObject::invokeMethod(map, "referenceLocationSelected", Qt::DirectConnection,
|
||||||
Q_ARG(double, 40.25), Q_ARG(double, 29.5)));
|
Q_ARG(double, 40.25), Q_ARG(double, 29.5)));
|
||||||
assert(referenceLatInput->text() == QStringLiteral("40.250000000000000"));
|
assert(referenceLatInput->text() == QStringLiteral("40.250000000000000"));
|
||||||
|
|||||||
Reference in New Issue
Block a user