summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gui/options-dialog.cpp21
-rw-r--r--gui/options-dialog.hpp3
-rw-r--r--gui/settings.ui82
-rw-r--r--gui/ui.cpp61
-rw-r--r--gui/ui.h3
-rw-r--r--opentrack-logic/main-settings.hpp6
-rw-r--r--opentrack-logic/state.hpp2
-rw-r--r--opentrack-logic/tracker.cpp22
-rw-r--r--opentrack-logic/tracker.h7
-rw-r--r--opentrack-logic/tracklogger.cpp28
-rw-r--r--opentrack-logic/tracklogger.hpp57
-rw-r--r--opentrack-logic/work.cpp4
-rw-r--r--opentrack-logic/work.hpp2
13 files changed, 290 insertions, 8 deletions
diff --git a/gui/options-dialog.cpp b/gui/options-dialog.cpp
index 3b54ae9a..8987ba34 100644
--- a/gui/options-dialog.cpp
+++ b/gui/options-dialog.cpp
@@ -11,6 +11,7 @@
#include <QPushButton>
#include <QLayout>
#include <QDialog>
+#include <QFileDialog>
static QString kopts_to_string(const key_opts& kopts)
{
@@ -72,6 +73,9 @@ OptionsDialog::OptionsDialog(std::function<void(bool)> pause_keybindings) :
tie_setting(main.center_method, ui.center_method);
+ tie_setting(main.tracklogging_enabled, ui.tracklogging_enabled);
+ tie_setting(main.tracklogging_filename, ui.tracklogging_filenameedit);
+
struct tmp
{
key_opts& opt;
@@ -102,6 +106,8 @@ OptionsDialog::OptionsDialog(std::function<void(bool)> pause_keybindings) :
connect(val.button, &QPushButton::pressed, this, [=]() -> void { bind_key(val.opt, val.label); });
}
}
+
+ connect(ui.tracklogging_fileselectbtn, SIGNAL(clicked()), this, SLOT(browse_datalogging_file()));
}
void OptionsDialog::bind_key(key_opts& kopts, QLabel* label)
@@ -163,3 +169,18 @@ void OptionsDialog::doCancel()
close();
}
+void OptionsDialog::browse_datalogging_file()
+{
+ QString filename = ui.tracklogging_filenameedit->text();
+ if (filename.isEmpty())
+ filename = QDir::currentPath();
+ QString newfilename = QFileDialog::getSaveFileName(this, tr("Select Filename"), filename, tr("CSV File (*.csv)"));
+ if (!newfilename.isEmpty())
+ ui.tracklogging_filenameedit->setText(newfilename);
+}
+
+void OptionsDialog::update_widgets_states(bool tracker_is_running)
+{
+ ui.tracklogging_enabled->setEnabled(!tracker_is_running);
+ ui.tracklogging_fileselectbtn->setEnabled(!tracker_is_running);
+} \ No newline at end of file
diff --git a/gui/options-dialog.hpp b/gui/options-dialog.hpp
index 66386a79..f84ee8f6 100644
--- a/gui/options-dialog.hpp
+++ b/gui/options-dialog.hpp
@@ -13,6 +13,8 @@ signals:
void saving();
public:
OptionsDialog(std::function<void(bool)> pause_keybindings);
+public slots:
+ void update_widgets_states(bool tracker_is_running);
private:
main_settings main;
std::function<void(bool)> pause_keybindings;
@@ -22,4 +24,5 @@ private slots:
void doOK();
void doCancel();
void bind_key(key_opts &kopts, QLabel* label);
+ void browse_datalogging_file();
};
diff --git a/gui/settings.ui b/gui/settings.ui
index 4654dd85..9c573da2 100644
--- a/gui/settings.ui
+++ b/gui/settings.ui
@@ -33,7 +33,7 @@
</sizepolicy>
</property>
<property name="currentIndex">
- <number>0</number>
+ <number>2</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@@ -1205,6 +1205,86 @@
</widget>
</item>
<item>
+ <widget class="QGroupBox" name="groupBox_10">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Data Logging</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QLabel" name="tracklogging_label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Record pose data in a csv file. WARNING: overwrites file contents without warning every time the tracker is started.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="tracklogging_enabled">
+ <property name="text">
+ <string>Enable</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="tracklogging_fileselectbtn">
+ <property name="text">
+ <string>Select File ...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="tracklogging_filenameedit">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="acceptDrops">
+ <bool>true</bool>
+ </property>
+ <property name="inputMask">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/gui/ui.cpp b/gui/ui.cpp
index 85d5d029..3bda6ee2 100644
--- a/gui/ui.cpp
+++ b/gui/ui.cpp
@@ -15,6 +15,7 @@
#include <QFileDialog>
#include <QDesktopServices>
#include <QCoreApplication>
+#include <cassert>
#ifdef _WIN32
# include <windows.h>
@@ -285,6 +286,45 @@ void MainWindow::reload_options()
ensure_tray();
}
+/*
+ Allocates a new logger instance depending on main settings. Result is assigned to logger variable of State object.
+ May open warning dialogs.
+ May also assign nullptr in case of an error.
+*/
+void MainWindow::initialize_logger()
+{
+ logger = nullptr;
+ if (s.tracklogging_enabled)
+ {
+ if (static_cast<QString>(s.tracklogging_filename).isEmpty())
+ {
+ QMessageBox::warning(this, tr("Logging Error"),
+ tr("No filename given for track logging. Aborting."),
+ QMessageBox::Ok,
+ QMessageBox::NoButton);
+ return;
+ }
+ try
+ {
+ logger = TrackLoggerCSV::make(s);
+ }
+ catch (std::ios_base::failure &)
+ {
+ QMessageBox::warning(this, tr("Logging Error"),
+ tr("Unable to open file: ") + s.tracklogging_filename + tr(". Aborting."),
+ QMessageBox::Ok,
+ QMessageBox::NoButton);
+ return;
+ }
+ }
+ else
+ {
+ logger = TrackLogger::make();
+ }
+ assert(logger != nullptr);
+}
+
+
void MainWindow::startTracker()
{
if (work)
@@ -310,9 +350,17 @@ void MainWindow::startTracker()
return;
}
+ initialize_logger();
+ if (logger == nullptr)
+ {
+ // error -> rollback
+ libs = SelectedLibraries();
+ return;
+ }
+
save_modules();
- work = std::make_shared<Work>(pose, libs, winId());
+ work = std::make_shared<Work>(pose, libs, *logger, winId());
reload_options();
@@ -331,6 +379,12 @@ void MainWindow::startTracker()
// trackers take care of layout state updates
const bool is_inertial = ui.video_frame->layout() == nullptr;
updateButtonState(true, is_inertial);
+
+ // Update the state of the options window directly.
+ // Might be better to emit signals and allow the options window
+ // to connect its slots to them (?)
+ if (options_widget)
+ options_widget->update_widgets_states(true);
ui.btnStopTracker->setFocus();
}
@@ -358,12 +412,16 @@ void MainWindow::stopTracker()
work = nullptr;
libs = SelectedLibraries();
+ logger = nullptr;
{
double p[6] = {0,0,0, 0,0,0};
display_pose(p, p);
}
updateButtonState(false, false);
+
+ if (options_widget)
+ options_widget->update_widgets_states(false);
set_title();
@@ -495,6 +553,7 @@ void MainWindow::show_options_dialog()
if (mk_window(&options_widget, [&](bool flag) -> void { set_keys_enabled(!flag); }))
{
connect(options_widget.get(), &OptionsDialog::saving, this, &MainWindow::reload_options);
+ options_widget->update_widgets_states(work != nullptr);
}
}
diff --git a/gui/ui.h b/gui/ui.h
index 7415d3d4..acec615e 100644
--- a/gui/ui.h
+++ b/gui/ui.h
@@ -102,6 +102,9 @@ private slots:
void startTracker();
void stopTracker();
void reload_options();
+
+ void initialize_logger();
+
signals:
void emit_start_tracker();
void emit_stop_tracker();
diff --git a/opentrack-logic/main-settings.hpp b/opentrack-logic/main-settings.hpp
index a7dcd11c..81eb99cf 100644
--- a/opentrack-logic/main-settings.hpp
+++ b/opentrack-logic/main-settings.hpp
@@ -73,6 +73,8 @@ struct main_settings
key_opts key_start_tracking, key_stop_tracking, key_toggle_tracking, key_restart_tracking;
key_opts key_center, key_toggle, key_zero;
key_opts key_toggle_press, key_zero_press;
+ value<bool> tracklogging_enabled;
+ value<QString> tracklogging_filename;
main_settings() :
b(bundle("opentrack-ui")),
a_x(b, "x", TX),
@@ -98,7 +100,9 @@ struct main_settings
key_toggle(b, "toggle"),
key_zero(b, "zero"),
key_toggle_press(b, "toggle-press"),
- key_zero_press(b, "zero-press")
+ key_zero_press(b, "zero-press"),
+ tracklogging_enabled(b, "tracklogging-enabled", false),
+ tracklogging_filename(b, "tracklogging-filename", QString())
{
}
};
diff --git a/opentrack-logic/state.hpp b/opentrack-logic/state.hpp
index 1c608f7a..bdab9afe 100644
--- a/opentrack-logic/state.hpp
+++ b/opentrack-logic/state.hpp
@@ -14,6 +14,7 @@ using namespace options;
#include "main-settings.hpp"
#include "mappings.hpp"
#include "selected-libraries.hpp"
+#include "tracklogger.hpp"
#include "work.hpp"
#include <vector>
#include <QString>
@@ -29,4 +30,5 @@ struct State
main_settings s;
Mappings pose;
mem<Work> work;
+ mem<TrackLogger> logger;
};
diff --git a/opentrack-logic/tracker.cpp b/opentrack-logic/tracker.cpp
index a1f206a1..8101932c 100644
--- a/opentrack-logic/tracker.cpp
+++ b/opentrack-logic/tracker.cpp
@@ -21,7 +21,7 @@
# include <windows.h>
#endif
-Tracker::Tracker(Mappings &m, SelectedLibraries &libs) :
+Tracker::Tracker(Mappings &m, SelectedLibraries &libs, TrackLogger &logger) :
m(m),
newpose {0,0,0, 0,0,0},
centerp(s.center_at_startup),
@@ -29,6 +29,7 @@ Tracker::Tracker(Mappings &m, SelectedLibraries &libs) :
zero_(false),
should_quit(false),
libs(libs),
+ logger(logger),
r_b(get_camera_offset_matrix().t()),
t_b {0,0,0}
{
@@ -134,6 +135,8 @@ void Tracker::logic()
raw(i) = newpose[i];
}
+ logger.write_pose(raw); // raw tracker input
+
if (is_nan(raw))
raw = last_raw;
@@ -207,10 +210,13 @@ void Tracker::logic()
}
}
+ logger.write_pose(value); // after various transformations to account for camera position
+
// whenever something can corrupt its internal state due to nan/inf, elide the call
if (is_nan(value))
{
nan = true;
+ logger.write_pose(value); // for consistency with filtered value
}
else
{
@@ -218,8 +224,11 @@ void Tracker::logic()
Pose tmp = value;
if (libs.pFilter)
+ {
libs.pFilter->filter(tmp, value);
+ }
}
+ logger.write_pose(value); // filtered value if filter present
// CAVEAT rotation only, due to tcomp
for (int i = 3; i < 6; i++)
@@ -256,6 +265,8 @@ void Tracker::logic()
for (int i = 0; i < 3; i++)
value(i) = map(value(i), m(i));
+ logger.write_pose(value); // after mapping
+
if (nan)
{
value = last_mapped;
@@ -265,6 +276,8 @@ void Tracker::logic()
(void) map(value(i), m(i));
}
+ logger.next_line();
+
libs.pProtocol->pose(value);
last_mapped = value;
@@ -283,8 +296,15 @@ void Tracker::run()
(void) timeBeginPeriod(1);
#endif
+ logger.write("//dt;raw;before filter;after filter;after mapping; every pose has channels TX, TY, TZ, Yaw, Pitch, Roll");
+ logger.next_line();
+
while (!should_quit)
{
+ {
+ double dt = t.elapsed_seconds();
+ logger.write(&dt, 1);
+ }
t.start();
double tmp[6] {0,0,0, 0,0,0};
diff --git a/opentrack-logic/tracker.h b/opentrack-logic/tracker.h
index fae8bd9e..b4d39a44 100644
--- a/opentrack-logic/tracker.h
+++ b/opentrack-logic/tracker.h
@@ -20,6 +20,7 @@
#include "spline-widget/functionconfig.h"
#include "main-settings.hpp"
#include "opentrack-compat/options.hpp"
+#include "tracklogger.hpp"
#include <QMutex>
#include <QThread>
@@ -62,6 +63,10 @@ private:
volatile bool zero_;
volatile bool should_quit;
SelectedLibraries const& libs;
+ // The owner of the reference is the main window.
+ // This design might be usefull if we decide later on to swap out
+ // the logger while the tracker is running.
+ TrackLogger &logger;
using rmat = euler::rmat;
using euler_t = euler::euler_t;
@@ -78,7 +83,7 @@ private:
static constexpr double r2d = 180. / OPENTRACK_PI;
static constexpr double d2r = OPENTRACK_PI / 180.;
public:
- Tracker(Mappings& m, SelectedLibraries& libs);
+ Tracker(Mappings& m, SelectedLibraries& libs, TrackLogger &logger);
~Tracker();
rmat get_camera_offset_matrix();
diff --git a/opentrack-logic/tracklogger.cpp b/opentrack-logic/tracklogger.cpp
new file mode 100644
index 00000000..5e4cf4f9
--- /dev/null
+++ b/opentrack-logic/tracklogger.cpp
@@ -0,0 +1,28 @@
+#include "tracklogger.hpp"
+#include "tracker.h"
+
+
+void TrackLoggerCSV::write(const char *s)
+{
+ out << s;
+}
+
+
+void TrackLoggerCSV::write(const double *p, int n)
+{
+ if (!first_col)
+ out.put(';');
+ first_col = false;
+ for (int i = 0; i < n-1; ++i)
+ {
+ out << p[i];
+ out.put(';');
+ }
+ out << p[n-1];
+}
+
+void TrackLoggerCSV::next_line()
+{
+ out << std::endl;
+ first_col = true;
+} \ No newline at end of file
diff --git a/opentrack-logic/tracklogger.hpp b/opentrack-logic/tracklogger.hpp
new file mode 100644
index 00000000..feed7fa2
--- /dev/null
+++ b/opentrack-logic/tracklogger.hpp
@@ -0,0 +1,57 @@
+#pragma once
+#include "main-settings.hpp"
+#include "opentrack-compat/options.hpp"
+
+#include <fstream>
+#include <QString>
+#include <QMessageBox>
+#include <QWidget>
+
+class OPENTRACK_LOGIC_EXPORT TrackLogger
+{
+public:
+ TrackLogger()
+ {
+ }
+
+ static mem<TrackLogger> make() { return std::make_shared<TrackLogger>(); }
+
+ virtual void write(const char *)
+ {
+ }
+
+ virtual void write(const double *, int n)
+ {
+ }
+
+ virtual void next_line()
+ {
+ }
+
+ void write_pose(const double *p)
+ {
+ write(p, 6);
+ }
+};
+
+
+class OPENTRACK_LOGIC_EXPORT TrackLoggerCSV : public TrackLogger
+{
+ std::ofstream out;
+ bool first_col;
+public:
+ TrackLoggerCSV(const QString &filename) : TrackLogger(),
+ first_col(true)
+ {
+ out.open(filename.toStdString());
+ if (!out.is_open())
+ throw std::ios_base::failure("unable to open file");
+ }
+
+ static mem<TrackLogger> make(const main_settings &s) { return std::static_pointer_cast<TrackLogger>(std::make_shared<TrackLoggerCSV>(s.tracklogging_filename)); }
+
+ virtual void write(const char *s);
+ virtual void write(const double *p, int n);
+ virtual void next_line();
+};
+
diff --git a/opentrack-logic/work.cpp b/opentrack-logic/work.cpp
index 820112bf..e5b08c18 100644
--- a/opentrack-logic/work.cpp
+++ b/opentrack-logic/work.cpp
@@ -1,9 +1,9 @@
#include "work.hpp"
-Work::Work(Mappings& m, SelectedLibraries& libs, WId handle) :
+Work::Work(Mappings& m, SelectedLibraries& libs, TrackLogger &logger, WId handle) :
libs(libs),
- tracker(std::make_shared<Tracker>(m, libs)),
+ tracker(std::make_shared<Tracker>(m, libs, logger)),
sc(std::make_shared<Shortcuts>()),
handle(handle),
keys {
diff --git a/opentrack-logic/work.hpp b/opentrack-logic/work.hpp
index 70322be2..6425b11c 100644
--- a/opentrack-logic/work.hpp
+++ b/opentrack-logic/work.hpp
@@ -33,7 +33,7 @@ struct OPENTRACK_LOGIC_EXPORT Work
std::vector<key_tuple> keys;
main_settings s;
- Work(Mappings& m, SelectedLibraries& libs, WId handle);
+ Work(Mappings& m, SelectedLibraries& libs, TrackLogger &logger, WId handle);
~Work();
void reload_shortcuts();
};