Add fusion trajectory replay view
This commit is contained in:
+20
-1
@@ -49,6 +49,10 @@ QString normalizeKey(QString key)
|
||||
return "satellites";
|
||||
}
|
||||
|
||||
if (key == "tracked") {
|
||||
return "satellites";
|
||||
}
|
||||
|
||||
if (key == "gdop" || key == "pdop" || key == "hdop" || key == "vdop" || key == "tdop") {
|
||||
return key;
|
||||
}
|
||||
@@ -76,7 +80,7 @@ std::optional<ParsedTelemetry> LocationParser::parseLine(const QString &line)
|
||||
}
|
||||
|
||||
static const QRegularExpression labeledValueRegex(
|
||||
QStringLiteral(R"((^|[^A-Za-z0-9_])(?<key>lat(?:t?itude)?|long(?:itude)?|lon|lng|hheight|height|alt(?:itude)?|active[_ -]?sat(?:ellite)?s?|num(?:ber)?[_ -]?sat(?:ellite)?s?|sat(?:ellite)?s?[_ -]?active|sat(?:ellite)?s?|sats|uydu(?:lar)?|[gphvt][_ -]?dop)(?:\s*(?:=|:|->)?\s*)(?<value>[+-]?(?:\d+(?:[\.,]\d+)?|[\.,]\d+)(?:[eE][+-]?\d+)?))"),
|
||||
QStringLiteral(R"((^|[^A-Za-z0-9_])(?<key>lat(?:t?itude)?|long(?:itude)?|lon|lng|hheight|height|alt(?:itude)?|active[_ -]?sat(?:ellite)?s?|num(?:ber)?[_ -]?sat(?:ellite)?s?|sat(?:ellite)?s?[_ -]?active|sat(?:ellite)?s?|sats|tracked|uydu(?:lar)?|[gphvt][_ -]?dop)(?:\s*(?:=|:|->)?\s*)(?<value>[+-]?(?:\d+(?:[\.,]\d+)?|[\.,]\d+)(?:[eE][+-]?\d+)?))"),
|
||||
QRegularExpression::CaseInsensitiveOption);
|
||||
static const QRegularExpression satelliteCountPhraseRegex(
|
||||
QStringLiteral(R"((^|[^A-Za-z0-9_\.])(?<value>\d+)\s+(?:active\s+)?(?:sat(?:ellite)?s?|uydu(?:lar)?)(?=$|[\s,.;)\]]))"),
|
||||
@@ -84,6 +88,21 @@ std::optional<ParsedTelemetry> LocationParser::parseLine(const QString &line)
|
||||
|
||||
ParsedTelemetry telemetry;
|
||||
telemetry.rawLine = trimmed;
|
||||
static const QRegularExpression sourceRegex(
|
||||
QStringLiteral(R"((?:^|\s)source\s*=\s*(?<source>gps|imu[_-]?corrected|trajectory|ground[_-]?truth)(?=$|\s))"),
|
||||
QRegularExpression::CaseInsensitiveOption);
|
||||
const QRegularExpressionMatch sourceMatch = sourceRegex.match(trimmed);
|
||||
if (sourceMatch.hasMatch()) {
|
||||
const QString source = sourceMatch.captured(QStringLiteral("source"));
|
||||
if (source.startsWith(QStringLiteral("imu"), Qt::CaseInsensitive)) {
|
||||
telemetry.source = LocationSource::ImuCorrected;
|
||||
} else if (source.startsWith(QStringLiteral("trajectory"), Qt::CaseInsensitive)
|
||||
|| source.startsWith(QStringLiteral("ground"), Qt::CaseInsensitive)) {
|
||||
telemetry.source = LocationSource::Trajectory;
|
||||
} else {
|
||||
telemetry.source = LocationSource::Gps;
|
||||
}
|
||||
}
|
||||
bool hadCoordinateField = false;
|
||||
bool hadLatitudeField = false;
|
||||
bool hadLongitudeField = false;
|
||||
|
||||
+76
-9
@@ -14,6 +14,8 @@
|
||||
#include <QDir>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHeaderView>
|
||||
@@ -155,6 +157,17 @@ LocationAnalysis analyzeLocations(const QVector<TelemetryPoint> &points)
|
||||
return analysis;
|
||||
}
|
||||
|
||||
QVector<TelemetryPoint> preferredAnalysisPoints(const QVector<TelemetryPoint> &points)
|
||||
{
|
||||
QVector<TelemetryPoint> corrected;
|
||||
for (const TelemetryPoint &point : points) {
|
||||
if (point.source == LocationSource::ImuCorrected) {
|
||||
corrected.push_back(point);
|
||||
}
|
||||
}
|
||||
return corrected.isEmpty() ? points : corrected;
|
||||
}
|
||||
|
||||
QString metersText(double meters)
|
||||
{
|
||||
if (!std::isfinite(meters)) {
|
||||
@@ -255,7 +268,7 @@ public:
|
||||
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override
|
||||
{
|
||||
return parent.isValid() ? 0 : 6;
|
||||
return parent.isValid() ? 0 : 7;
|
||||
}
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
|
||||
@@ -275,14 +288,16 @@ public:
|
||||
case 0:
|
||||
return point.receivedAt.toLocalTime().toString(QStringLiteral("HH:mm:ss.zzz"));
|
||||
case 1:
|
||||
return coordinateText(point.latitude, point.latitudeText);
|
||||
return locationSourceText(point.source);
|
||||
case 2:
|
||||
return coordinateText(point.longitude, point.longitudeText);
|
||||
return coordinateText(point.latitude, point.latitudeText);
|
||||
case 3:
|
||||
return optionalDoubleText(point.hheight, 2);
|
||||
return coordinateText(point.longitude, point.longitudeText);
|
||||
case 4:
|
||||
return optionalIntText(point.satellites);
|
||||
return optionalDoubleText(point.hheight, 2);
|
||||
case 5:
|
||||
return optionalIntText(point.satellites);
|
||||
case 6:
|
||||
return optionalDopText(point.dop.pdop);
|
||||
default:
|
||||
return {};
|
||||
@@ -296,7 +311,7 @@ public:
|
||||
return {};
|
||||
}
|
||||
static const QStringList headers = {
|
||||
QStringLiteral("Saat"), QStringLiteral("Lat"), QStringLiteral("Long"),
|
||||
QStringLiteral("Saat"), QStringLiteral("Kaynak"), QStringLiteral("Lat"), QStringLiteral("Long"),
|
||||
QStringLiteral("HHeight"), QStringLiteral("Uydu"), QStringLiteral("PDOP")};
|
||||
return section >= 0 && section < headers.size() ? headers[section] : QVariant();
|
||||
}
|
||||
@@ -366,6 +381,50 @@ void MainWindow::clearPoints()
|
||||
resetTelemetryState();
|
||||
}
|
||||
|
||||
bool MainWindow::loadTelemetryLog(const QString &filePath)
|
||||
{
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
const QString message = QStringLiteral("Log acilamadi: %1").arg(file.errorString());
|
||||
m_statusLabel->setText(message);
|
||||
statusBar()->showMessage(message, 8000);
|
||||
return false;
|
||||
}
|
||||
const QList<QByteArray> lines = file.readAll().split('\n');
|
||||
resetTelemetryState();
|
||||
const int replayCapacity = static_cast<int>(std::min<qsizetype>(10000, lines.size()));
|
||||
m_maxPointsSpin->setValue(std::max(10, replayCapacity));
|
||||
int parsedLocations = 0;
|
||||
for (const QByteArray &rawLine : lines) {
|
||||
const QString line = QString::fromUtf8(rawLine).trimmed();
|
||||
if (line.isEmpty() || line.startsWith(QLatin1Char('#'))) {
|
||||
continue;
|
||||
}
|
||||
const auto telemetry = LocationParser::parseLine(line);
|
||||
if (telemetry.has_value() && telemetry->hasLocation()) {
|
||||
++parsedLocations;
|
||||
}
|
||||
handleSerialLine(line);
|
||||
}
|
||||
flushUiUpdates();
|
||||
m_map->fitToPoints();
|
||||
const QString message = QStringLiteral("Replay yuklendi: %1 konum - %2")
|
||||
.arg(parsedLocations).arg(filePath);
|
||||
m_statusLabel->setText(message);
|
||||
statusBar()->showMessage(message, 8000);
|
||||
return parsedLocations > 0;
|
||||
}
|
||||
|
||||
void MainWindow::openTelemetryLog()
|
||||
{
|
||||
const QString filePath = QFileDialog::getOpenFileName(
|
||||
this, QStringLiteral("Sentetik telemetri logunu ac"), QString(),
|
||||
QStringLiteral("Telemetry logs (*.log *.txt);;All files (*)"));
|
||||
if (!filePath.isEmpty()) {
|
||||
loadTelemetryLog(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::handleSerialLine(const QString &line)
|
||||
{
|
||||
static const QRegularExpression solveStartRegex(
|
||||
@@ -698,6 +757,9 @@ void MainWindow::buildUi()
|
||||
m_connectButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
|
||||
m_clearButton = new QPushButton(QStringLiteral("Temizle"), this);
|
||||
m_clearButton->setIcon(style()->standardIcon(QStyle::SP_TrashIcon));
|
||||
m_openLogButton = new QPushButton(QStringLiteral("Senaryo Logu Ac"), this);
|
||||
m_openLogButton->setObjectName(QStringLiteral("openLogButton"));
|
||||
m_openLogButton->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton));
|
||||
|
||||
m_autoFollowCheck = new QCheckBox(QStringLiteral("Kamerayi takip et"), this);
|
||||
m_autoFollowCheck->setChecked(true);
|
||||
@@ -716,6 +778,7 @@ void MainWindow::buildUi()
|
||||
toolbarLayout->addWidget(new QLabel(QStringLiteral("Max"), this));
|
||||
toolbarLayout->addWidget(m_maxPointsSpin);
|
||||
toolbarLayout->addWidget(m_connectButton);
|
||||
toolbarLayout->addWidget(m_openLogButton);
|
||||
toolbarLayout->addWidget(m_clearButton);
|
||||
toolbarLayout->addWidget(m_autoFollowCheck);
|
||||
toolbarLayout->addWidget(zoomOutButton);
|
||||
@@ -932,6 +995,7 @@ void MainWindow::buildUi()
|
||||
|
||||
connect(m_connectButton, &QPushButton::clicked, this, &MainWindow::toggleSerial);
|
||||
connect(m_clearButton, &QPushButton::clicked, this, &MainWindow::clearPoints);
|
||||
connect(m_openLogButton, &QPushButton::clicked, this, &MainWindow::openTelemetryLog);
|
||||
connect(m_maxPointsSpin, qOverload<int>(&QSpinBox::valueChanged), this,
|
||||
&MainWindow::trimToMaxPoints);
|
||||
connect(m_autoFollowCheck, &QCheckBox::toggled, m_map, &MapWidget::setAutoFollow);
|
||||
@@ -974,6 +1038,7 @@ void MainWindow::updateConnectionControls()
|
||||
void MainWindow::addTelemetryPoint(const ParsedTelemetry &telemetry)
|
||||
{
|
||||
TelemetryPoint point;
|
||||
point.source = telemetry.source;
|
||||
point.latitude = *telemetry.latitude;
|
||||
point.longitude = *telemetry.longitude;
|
||||
point.latitudeText = telemetry.latitudeText;
|
||||
@@ -1028,7 +1093,8 @@ void MainWindow::updateDopLabels()
|
||||
|
||||
void MainWindow::updateAnalysis()
|
||||
{
|
||||
const LocationAnalysis analysis = analyzeLocations(m_points);
|
||||
const QVector<TelemetryPoint> analysisPoints = preferredAnalysisPoints(m_points);
|
||||
const LocationAnalysis analysis = analyzeLocations(analysisPoints);
|
||||
if (!analysis.valid) {
|
||||
m_cepLabel->setText(QStringLiteral("-"));
|
||||
m_meanLocationLabel->setText(QStringLiteral("-"));
|
||||
@@ -1051,11 +1117,11 @@ void MainWindow::updateAnalysis()
|
||||
m_map->setAverageMarker(analysis.averageLat, analysis.averageLon,
|
||||
analysis.rmsScatterMeters);
|
||||
|
||||
const double cep50 = calculateCep50(m_points, analysis.averageLat,
|
||||
const double cep50 = calculateCep50(analysisPoints, analysis.averageLat,
|
||||
analysis.averageLon);
|
||||
m_cepLabel->setText(QStringLiteral("%1 (P50, N=%2)")
|
||||
.arg(metersText(cep50))
|
||||
.arg(m_points.size()));
|
||||
.arg(analysisPoints.size()));
|
||||
m_map->setCepMarker(analysis.averageLat, analysis.averageLon, cep50);
|
||||
}
|
||||
|
||||
@@ -1078,6 +1144,7 @@ void MainWindow::mergePendingTelemetry(const ParsedTelemetry &telemetry)
|
||||
}
|
||||
|
||||
if (telemetry.latitude.has_value()) {
|
||||
m_pendingTelemetry.source = telemetry.source;
|
||||
m_pendingTelemetry.latitude = telemetry.latitude;
|
||||
m_pendingTelemetry.latitudeText = telemetry.latitudeText;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ class MainWindow : public QMainWindow {
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
bool loadTelemetryLog(const QString &filePath);
|
||||
|
||||
private slots:
|
||||
void toggleSerial();
|
||||
@@ -41,6 +42,7 @@ private slots:
|
||||
void trimToMaxPoints();
|
||||
void updateReferenceLocation();
|
||||
void flushUiUpdates();
|
||||
void openTelemetryLog();
|
||||
|
||||
private:
|
||||
void buildUi();
|
||||
@@ -70,6 +72,7 @@ private:
|
||||
QLineEdit *m_referenceLonEdit = nullptr;
|
||||
QPushButton *m_connectButton = nullptr;
|
||||
QPushButton *m_clearButton = nullptr;
|
||||
QPushButton *m_openLogButton = nullptr;
|
||||
QCheckBox *m_autoFollowCheck = nullptr;
|
||||
QCheckBox *m_showTelemetryCheck = nullptr;
|
||||
QCheckBox *m_showRecentPointsCheck = nullptr;
|
||||
|
||||
+100
-17
@@ -108,6 +108,41 @@ void MapWidget::clearPoints()
|
||||
update();
|
||||
}
|
||||
|
||||
void MapWidget::fitToPoints()
|
||||
{
|
||||
if (m_points.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
double minimumLatitude = m_points.first().latitude;
|
||||
double maximumLatitude = minimumLatitude;
|
||||
double minimumLongitude = m_points.first().longitude;
|
||||
double maximumLongitude = minimumLongitude;
|
||||
for (const TelemetryPoint &point : m_points) {
|
||||
minimumLatitude = std::min(minimumLatitude, point.latitude);
|
||||
maximumLatitude = std::max(maximumLatitude, point.latitude);
|
||||
minimumLongitude = std::min(minimumLongitude, point.longitude);
|
||||
maximumLongitude = std::max(maximumLongitude, point.longitude);
|
||||
}
|
||||
m_centerLat = 0.5 * (minimumLatitude + maximumLatitude);
|
||||
m_centerLon = 0.5 * (minimumLongitude + maximumLongitude);
|
||||
const double availableWidth = std::max(100.0, width() * 0.82);
|
||||
const double availableHeight = std::max(100.0, height() * 0.82);
|
||||
for (int zoom = MaxZoom; zoom >= MinZoom; --zoom) {
|
||||
const QPointF topLeft = coordinateToWorld(maximumLatitude, minimumLongitude, zoom);
|
||||
const QPointF bottomRight = coordinateToWorld(minimumLatitude, maximumLongitude, zoom);
|
||||
if (std::fabs(bottomRight.x() - topLeft.x()) <= availableWidth
|
||||
&& std::fabs(bottomRight.y() - topLeft.y()) <= availableHeight) {
|
||||
m_zoom = zoom;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_autoFollow) {
|
||||
m_autoFollow = false;
|
||||
emit autoFollowChanged(false);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void MapWidget::setAverageMarker(double latitude, double longitude, double radiusMeters)
|
||||
{
|
||||
m_hasAverageMarker = true;
|
||||
@@ -216,6 +251,7 @@ void MapWidget::paintEvent(QPaintEvent *)
|
||||
painter.fillRect(rect(), QColor(219, 225, 220));
|
||||
drawTiles(painter);
|
||||
drawTelemetry(painter);
|
||||
drawLegend(painter);
|
||||
|
||||
if (m_points.isEmpty()) {
|
||||
drawEmptyState(painter);
|
||||
@@ -387,23 +423,31 @@ void MapWidget::drawTelemetry(QPainter &painter)
|
||||
|
||||
drawCepOverlay(painter);
|
||||
|
||||
QPainterPath path;
|
||||
for (int i = 0; i < m_points.size(); ++i) {
|
||||
const QPointF screen = coordinateToScreen(m_points[i].latitude, m_points[i].longitude);
|
||||
if (i == 0) {
|
||||
path.moveTo(screen);
|
||||
} else {
|
||||
path.lineTo(screen);
|
||||
const auto drawSourcePath = [this, &painter](LocationSource source, const QColor &color) {
|
||||
QPainterPath path;
|
||||
bool havePoint = false;
|
||||
int pointCount = 0;
|
||||
for (const TelemetryPoint &point : m_points) {
|
||||
if (point.source != source) {
|
||||
continue;
|
||||
}
|
||||
const QPointF screen = coordinateToScreen(point.latitude, point.longitude);
|
||||
havePoint ? path.lineTo(screen) : path.moveTo(screen);
|
||||
havePoint = true;
|
||||
++pointCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_showRecentPoints && m_points.size() > 1) {
|
||||
QPen pathPen(QColor(210, 105, 30), 3.0);
|
||||
pathPen.setCapStyle(Qt::RoundCap);
|
||||
pathPen.setJoinStyle(Qt::RoundJoin);
|
||||
painter.setPen(pathPen);
|
||||
painter.drawPath(path);
|
||||
}
|
||||
if (m_showRecentPoints && pointCount > 1) {
|
||||
QPen pathPen(color, 3.0);
|
||||
pathPen.setCapStyle(Qt::RoundCap);
|
||||
pathPen.setJoinStyle(Qt::RoundJoin);
|
||||
painter.setPen(pathPen);
|
||||
painter.drawPath(path);
|
||||
}
|
||||
};
|
||||
drawSourcePath(LocationSource::Trajectory, QColor(22, 163, 74));
|
||||
drawSourcePath(LocationSource::Generic, QColor(210, 105, 30));
|
||||
drawSourcePath(LocationSource::Gps, QColor(37, 99, 235));
|
||||
drawSourcePath(LocationSource::ImuCorrected, QColor(220, 38, 38));
|
||||
|
||||
drawAverageOverlay(painter);
|
||||
drawCepMarker(painter);
|
||||
@@ -415,8 +459,15 @@ void MapWidget::drawTelemetry(QPainter &painter)
|
||||
const QPointF screen = coordinateToScreen(m_points[i].latitude, m_points[i].longitude);
|
||||
const double radius = isLast ? 8.0 : 5.0;
|
||||
|
||||
const QColor pointColor = m_points[i].source == LocationSource::ImuCorrected
|
||||
? QColor(220, 38, 38)
|
||||
: (m_points[i].source == LocationSource::Gps
|
||||
? QColor(37, 99, 235)
|
||||
: (m_points[i].source == LocationSource::Trajectory
|
||||
? QColor(22, 163, 74)
|
||||
: (isLast ? QColor(210, 105, 30) : QColor(234, 88, 12))));
|
||||
painter.setPen(QPen(Qt::white, isLast ? 3.0 : 2.0));
|
||||
painter.setBrush(isLast ? QColor(31, 150, 82) : QColor(37, 99, 235));
|
||||
painter.setBrush(pointColor);
|
||||
painter.drawEllipse(screen, radius, radius);
|
||||
|
||||
if (drawNumbers) {
|
||||
@@ -436,6 +487,7 @@ void MapWidget::drawTelemetry(QPainter &painter)
|
||||
? QString::number(last.longitude, 'f', 15) : last.longitudeText;
|
||||
lines << QStringLiteral("Lat: %1").arg(latitudeText);
|
||||
lines << QStringLiteral("Long: %1").arg(longitudeText);
|
||||
lines << QStringLiteral("Kaynak: %1").arg(locationSourceText(last.source));
|
||||
if (last.hheight.has_value()) {
|
||||
lines << QStringLiteral("HHeight: %1").arg(*last.hheight, 0, 'f', 2);
|
||||
}
|
||||
@@ -466,6 +518,37 @@ void MapWidget::drawTelemetry(QPainter &painter)
|
||||
painter.drawText(bubble.adjusted(9, 7, -9, -7), Qt::AlignLeft | Qt::AlignVCenter, label);
|
||||
}
|
||||
|
||||
void MapWidget::drawLegend(QPainter &painter)
|
||||
{
|
||||
if (m_points.isEmpty() || !m_showTelemetryOverlay) {
|
||||
return;
|
||||
}
|
||||
const struct {
|
||||
const char *text;
|
||||
QColor color;
|
||||
} entries[] = {
|
||||
{"Trajectory (truth)", QColor(22, 163, 74)},
|
||||
{"GPS (4 satellite)", QColor(37, 99, 235)},
|
||||
{"IMU + ESKF corrected", QColor(220, 38, 38)}
|
||||
};
|
||||
const QRectF box(12.0, 12.0, 190.0, 76.0);
|
||||
painter.setPen(QPen(QColor(50, 58, 65, 180), 1.0));
|
||||
painter.setBrush(QColor(255, 255, 255, 232));
|
||||
painter.drawRoundedRect(box, 6.0, 6.0);
|
||||
painter.setFont(QFont(painter.font().family(), 9, QFont::DemiBold));
|
||||
for (int index = 0; index < 3; ++index) {
|
||||
const double y = 27.0 + index * 22.0;
|
||||
painter.setPen(QPen(entries[index].color, 3.0));
|
||||
painter.drawLine(QPointF(23.0, y), QPointF(43.0, y));
|
||||
painter.setBrush(entries[index].color);
|
||||
painter.drawEllipse(QPointF(33.0, y), 4.0, 4.0);
|
||||
painter.setPen(QColor(25, 32, 38));
|
||||
painter.drawText(QRectF(50.0, y - 9.0, 142.0, 18.0),
|
||||
Qt::AlignLeft | Qt::AlignVCenter,
|
||||
QString::fromLatin1(entries[index].text));
|
||||
}
|
||||
}
|
||||
|
||||
void MapWidget::drawCepOverlay(QPainter &painter)
|
||||
{
|
||||
if (!m_hasCepMarker || !m_cepRadiusMeters.has_value() || *m_cepRadiusMeters <= 0.0) {
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
explicit MapWidget(QWidget *parent = nullptr);
|
||||
|
||||
void setPoints(const QVector<TelemetryPoint> &points);
|
||||
void fitToPoints();
|
||||
void clearPoints();
|
||||
void setAverageMarker(double latitude, double longitude, double radiusMeters);
|
||||
void clearAverageMarker();
|
||||
@@ -56,6 +57,7 @@ private:
|
||||
|
||||
void drawTiles(QPainter &painter);
|
||||
void drawTelemetry(QPainter &painter);
|
||||
void drawLegend(QPainter &painter);
|
||||
void drawAverageOverlay(QPainter &painter);
|
||||
void drawCepOverlay(QPainter &painter);
|
||||
void drawCepMarker(QPainter &painter);
|
||||
|
||||
@@ -5,6 +5,28 @@
|
||||
|
||||
#include <optional>
|
||||
|
||||
enum class LocationSource {
|
||||
Generic,
|
||||
Gps,
|
||||
ImuCorrected,
|
||||
Trajectory
|
||||
};
|
||||
|
||||
inline QString locationSourceText(LocationSource source)
|
||||
{
|
||||
switch (source) {
|
||||
case LocationSource::Gps:
|
||||
return QStringLiteral("GPS");
|
||||
case LocationSource::ImuCorrected:
|
||||
return QStringLiteral("IMU corrected");
|
||||
case LocationSource::Trajectory:
|
||||
return QStringLiteral("Trajectory (truth)");
|
||||
case LocationSource::Generic:
|
||||
default:
|
||||
return QStringLiteral("Generic");
|
||||
}
|
||||
}
|
||||
|
||||
struct DopValues {
|
||||
std::optional<double> gdop;
|
||||
std::optional<double> pdop;
|
||||
@@ -20,6 +42,7 @@ struct DopValues {
|
||||
};
|
||||
|
||||
struct TelemetryPoint {
|
||||
LocationSource source = LocationSource::Generic;
|
||||
double latitude = 0.0;
|
||||
double longitude = 0.0;
|
||||
QString latitudeText;
|
||||
@@ -32,6 +55,7 @@ struct TelemetryPoint {
|
||||
};
|
||||
|
||||
struct ParsedTelemetry {
|
||||
LocationSource source = LocationSource::Generic;
|
||||
std::optional<double> latitude;
|
||||
std::optional<double> longitude;
|
||||
QString latitudeText;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -9,6 +10,9 @@ int main(int argc, char *argv[])
|
||||
QApplication::setOrganizationName(QStringLiteral("rocket"));
|
||||
|
||||
MainWindow window;
|
||||
if (argc == 3 && QString::fromLocal8Bit(argv[1]) == QStringLiteral("--replay")) {
|
||||
window.loadTelemetryLog(QFileInfo(QString::fromLocal8Bit(argv[2])).absoluteFilePath());
|
||||
}
|
||||
window.show();
|
||||
|
||||
return QApplication::exec();
|
||||
|
||||
Reference in New Issue
Block a user