From 98e48a3585448f5f12442a0f1304f15e759f18f7 Mon Sep 17 00:00:00 2001 From: "d.kilic" <d.kilic@fz-juelich.de> Date: Tue, 6 Jul 2021 09:17:44 +0000 Subject: [PATCH] Resolve "Add Support for mutliple MoCap-Files" - changed dialogue "Open MoCap" to "Manage MoCap" - enable loading multiple MoCap-Files (or same with different offset) - enable unloading MoCap-Files - save all files in pet and load when opening project --- CMakeLists.txt | 3 + include/moCapPersonMetadata.h | 4 +- include/moCapSelectionWidget.h | 38 +++++++++++ include/openMoCapDialog.h | 4 +- include/petrack.h | 1 - src/moCapPersonMetadata.cpp | 8 +-- src/moCapSelectionWidget.cpp | 97 ++++++++++++++++++++++++++++ src/openMoCapDialog.cpp | 95 +++++++++++++++------------- src/petrack.cpp | 4 +- ui/moCapSelectionWidget.ui | 105 +++++++++++++++++++++++++++++++ ui/openMoCapDialog.ui | 111 ++++++++++++++++++++------------- 11 files changed, 374 insertions(+), 96 deletions(-) create mode 100644 include/moCapSelectionWidget.h create mode 100644 src/moCapSelectionWidget.cpp create mode 100644 ui/moCapSelectionWidget.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index b187aa3cd..5c26888be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -326,6 +326,7 @@ target_sources(petrack_core PRIVATE include/openMoCapDialog.h include/moCapPersonMetadata.h include/pMessageBox.h + include/moCapSelectionWidget.h ) target_sources(petrack_core PRIVATE @@ -384,6 +385,7 @@ target_sources(petrack_core PRIVATE src/openMoCapDialog.cpp src/moCapPersonMetadata.cpp src/pMessageBox.cpp + src/moCapSelectionWidget.cpp ui/about.ui ui/codeMarker.ui ui/colorMarker.ui @@ -392,6 +394,7 @@ target_sources(petrack_core PRIVATE ui/stereo.ui ui/control.ui ui/openMoCapDialog.ui + ui/moCapSelectionWidget.ui ) target_sources(petrack PRIVATE diff --git a/include/moCapPersonMetadata.h b/include/moCapPersonMetadata.h index a8d0de67f..e09c581bf 100644 --- a/include/moCapPersonMetadata.h +++ b/include/moCapPersonMetadata.h @@ -46,12 +46,12 @@ public: MoCapPersonMetadata& operator=(const MoCapPersonMetadata&) = default; MoCapPersonMetadata& operator=(MoCapPersonMetadata&&) = default; ~MoCapPersonMetadata() = default; - MoCapPersonMetadata(std::string filepath, MoCapSystem system, int samplerate, double offset); + MoCapPersonMetadata(std::string filepath, MoCapSystem system, double samplerate, double offset); void setFilepath(const std::string &filepath, MoCapSystem system); void setSamplerate(double samplerate); void setOffset(double offset); - void setMetadata(const std::string &filepath, MoCapSystem, int samplerate, double offset); + void setMetadata(const std::string &filepath, MoCapSystem, double samplerate, double offset); MoCapSystem getSystem() const; double getSamplerate() const; double getOffset() const; diff --git a/include/moCapSelectionWidget.h b/include/moCapSelectionWidget.h new file mode 100644 index 000000000..837af10a0 --- /dev/null +++ b/include/moCapSelectionWidget.h @@ -0,0 +1,38 @@ +#ifndef MOCAPSELECTIONWIDGET_H +#define MOCAPSELECTIONWIDGET_H + +#include <QWidget> + +#include "moCapPersonMetadata.h" + +namespace Ui { + class MoCapSelectionWidget; +} +class OpenMoCapDialog; + +class MoCapSelectionWidget : public QWidget +{ + Q_OBJECT + +public: + explicit MoCapSelectionWidget(QWidget *parent, const QMap<QString, MoCapSystem>& moCapSystems); + explicit MoCapSelectionWidget(QWidget *parent, const QMap<QString, MoCapSystem>& moCapSystems, const MoCapPersonMetadata& metadata); + MoCapSelectionWidget(const MoCapSelectionWidget&) = delete; + MoCapSelectionWidget(MoCapSelectionWidget&&) = delete; + MoCapSelectionWidget& operator=(const MoCapSelectionWidget&) = delete; + MoCapSelectionWidget& operator=(MoCapSelectionWidget&&) = delete; + ~MoCapSelectionWidget() override; + + void setFileName(); + MoCapPersonMetadata getMetadata() const; + + bool isFilledOut() const; + +private: + Ui::MoCapSelectionWidget *mUi; + const QMap<QString, MoCapSystem>& mMoCapSystems; + bool mFilledOut = false; + +}; + +#endif // MOCAPSELECTIONWIDGET_H diff --git a/include/openMoCapDialog.h b/include/openMoCapDialog.h index 2a4b55044..707d41574 100644 --- a/include/openMoCapDialog.h +++ b/include/openMoCapDialog.h @@ -52,9 +52,11 @@ public: OpenMoCapDialog& operator=(OpenMoCapDialog&&) = delete; ~OpenMoCapDialog() override; - void setFileName(); void clickedOk(); +private slots: + void on_btnAddSelection_clicked(); + private: Ui::OpenMoCapDialog *mUi; QMap<QString, MoCapSystem> mMoCapSystems; diff --git a/include/petrack.h b/include/petrack.h index a338d6fdc..43d8cabb9 100644 --- a/include/petrack.h +++ b/include/petrack.h @@ -39,7 +39,6 @@ #include "autoCalib.h" #include "coordItem.h" #include "extrCalibration.h" -#include "openMoCapDialog.h" #include "moCapPerson.h" #include "moCapController.h" diff --git a/src/moCapPersonMetadata.cpp b/src/moCapPersonMetadata.cpp index 37aa6252d..4f3926100 100644 --- a/src/moCapPersonMetadata.cpp +++ b/src/moCapPersonMetadata.cpp @@ -20,12 +20,12 @@ #include <QFileInfo> #include "moCapPersonMetadata.h" -MoCapPersonMetadata::MoCapPersonMetadata(std::string filepath, MoCapSystem system, int samplerate, double offset){ +MoCapPersonMetadata::MoCapPersonMetadata(std::string filepath, MoCapSystem system, double samplerate, double offset){ setMetadata(filepath, system, samplerate, offset); } -void MoCapPersonMetadata::setMetadata(const std::string &filepath, MoCapSystem system, int samplerate, double offset){ +void MoCapPersonMetadata::setMetadata(const std::string &filepath, MoCapSystem system, double samplerate, double offset){ setSamplerate(samplerate); setOffset(offset); setFilepath(filepath, system); @@ -86,8 +86,8 @@ double MoCapPersonMetadata::getOffset() const { bool operator==(const MoCapPersonMetadata &lhs, const MoCapPersonMetadata &rhs){ return (lhs.getFilepath().compare(rhs.getFilepath()) == 0 - && lhs.getOffset() == rhs.getOffset() - && lhs.getSamplerate() == rhs.getSamplerate() + && std::abs(lhs.getOffset() - rhs.getOffset()) < 1e-4 + && std::abs(lhs.getSamplerate() - rhs.getSamplerate()) < 1e-4 && lhs.getSystem() == rhs.getSystem()); } diff --git a/src/moCapSelectionWidget.cpp b/src/moCapSelectionWidget.cpp new file mode 100644 index 000000000..d216f82f0 --- /dev/null +++ b/src/moCapSelectionWidget.cpp @@ -0,0 +1,97 @@ +#include <QFileDialog> + +#include "moCapSelectionWidget.h" +#include "ui_moCapSelectionWidget.h" +#include "openMoCapDialog.h" + +MoCapSelectionWidget::MoCapSelectionWidget(QWidget *parent, const QMap<QString, MoCapSystem>& moCapSystems) : + QWidget(parent), + mUi(new Ui::MoCapSelectionWidget), + mMoCapSystems(moCapSystems) +{ + mUi->setupUi(this); + + constexpr int defaultSampleRate = 60; + constexpr double offsetRange = 5; + + mUi->btnDelete->setIcon(QApplication::style()->standardIcon(QStyle::SP_TrashIcon)); + mUi->cbInputSystem->addItems(QStringList(moCapSystems.keys())); + mUi->cbInputSystem->setCurrentIndex(0); + mUi->sampleRateSpinBox->setRange(1, 300); + mUi->sampleRateSpinBox->setValue(defaultSampleRate); + mUi->offSetSpinBox->setRange(-offsetRange, offsetRange); + mUi->offSetSpinBox->setSingleStep(0.01); + + connect(mUi->browseFileButton, &QPushButton::clicked, this, &MoCapSelectionWidget::setFileName); + connect(mUi->btnDelete, &QPushButton::clicked, this, &MoCapSelectionWidget::deleteLater); +} + +/** + * @brief constructs a widget with the data from a Metadata-Object + * @param parent Widget parent (Qt) + * @param moCapSystems Map from QString in Combobox to MoCapSystem-Enum + * @param metadata Metadata which should be represented by this widget + */ +MoCapSelectionWidget::MoCapSelectionWidget(QWidget *parent, const QMap<QString, MoCapSystem> &moCapSystems, const MoCapPersonMetadata &metadata) : + MoCapSelectionWidget(parent, moCapSystems) +{ + auto usedMoCapSystem = std::find(moCapSystems.begin(), moCapSystems.end(), metadata.getSystem()); + if(usedMoCapSystem != moCapSystems.end()){ + mUi->cbInputSystem->setCurrentText(usedMoCapSystem.key()); + } + mUi->sampleRateSpinBox->setValue(metadata.getSamplerate()); + mUi->offSetSpinBox->setValue(metadata.getOffset()); + mUi->filePathLabel->setText(QString::fromStdString(metadata.getFilepath())); + mFilledOut = true; +} + +/** + * @brief Let user select a MoCapFile + * + * This method opens a file dialog which enabled the user + * to select a file fitting to the given MoCapSystem (e.g. c3d) + * + * If a file is selected, the widget counts as filled out. + * + * This method is called by a Signal('browse File'-Button). + */ +void MoCapSelectionWidget::setFileName(){ + std::stringstream extensionsString; + extensionsString << "All MoCap File Types ("; + for(const auto &extension: moCapFileExtensions){ + extensionsString << " *." << extension.second; + } + extensionsString << ")"; + QString filename = QFileDialog::getOpenFileName(this, tr("Open C3D File"), QDir::currentPath(), + QString::fromStdString(extensionsString.str())); + mUi->filePathLabel->clear(); + mUi->filePathLabel->setText(filename); + mFilledOut = !filename.isEmpty(); +} + +/** + * @brief Returns contained info as Metadata-Object + * + * This method returns the values saved in this widget as + * a MoCapPersonMetadata-Object. + * @return Metadata with data from this widget + */ +MoCapPersonMetadata MoCapSelectionWidget::getMetadata() const +{ + return MoCapPersonMetadata(mUi->filePathLabel->text().toStdString(), + mMoCapSystems[mUi->cbInputSystem->currentText()], + mUi->sampleRateSpinBox->value(), + mUi->offSetSpinBox->value()); +} + +bool MoCapSelectionWidget::isFilledOut() const +{ + return mFilledOut; +} + +MoCapSelectionWidget::~MoCapSelectionWidget() +{ + delete mUi; +} + +#include "moc_moCapSelectionWidget.cpp" diff --git a/src/openMoCapDialog.cpp b/src/openMoCapDialog.cpp index d51d66878..96e6d5a28 100644 --- a/src/openMoCapDialog.cpp +++ b/src/openMoCapDialog.cpp @@ -24,52 +24,32 @@ #include "ui_openMoCapDialog.h" #include "moCapPersonMetadata.h" +#include "moCapSelectionWidget.h" + OpenMoCapDialog::OpenMoCapDialog(QWidget *parent, MoCapController &controller) : QDialog(parent), mUi(new Ui::OpenMoCapDialog), mController(controller), mParent(parent) { - constexpr int defaultSampleRate = 60; - constexpr double offsetRange = 5; - mUi->setupUi(this); + + + mMoCapSystems = QMap<QString, MoCapSystem>(); setWindowFlags(windowFlags().setFlag(Qt::WindowContextHelpButtonHint, false)); mMoCapSystems.insert("XSensC3D", MoCapSystem::XSensC3D); - mUi->cbInputSystem->addItems(QStringList(mMoCapSystems.keys())); - mUi->cbInputSystem->setCurrentIndex(0); - mUi->sampleRateSpinBox->setRange(1, 300); - mUi->sampleRateSpinBox->setValue(defaultSampleRate); - mUi->offSetSpinBox->setRange(-offsetRange, offsetRange); - mUi->offSetSpinBox->setSingleStep(0.01); - mUi->filePathLineEdit->setReadOnly(true); - mUi->pushButtonOK->setDisabled(true); + + const auto loadedMetadata = mController.getAllMoCapPersonMetadata(); + for(const auto& metadata : loadedMetadata){ + mUi->moCapSelections->layout()->addWidget(new MoCapSelectionWidget(this, mMoCapSystems, metadata)); + } + connect(mUi->pushButtonOK, &QPushButton::clicked, this, &OpenMoCapDialog::clickedOk); connect(mUi->pushButtonCancel, &QPushButton::clicked, this, &OpenMoCapDialog::close); - connect(mUi->browseFileButton, &QPushButton::clicked, this, &OpenMoCapDialog::setFileName); } -/** - * @brief Opens QFileDialog and enables ok-Button if the selected filename isn't empty. - * - * This method is called by a Signal('browse File'-Button). - * The selected Filename is shown(read-only) in the LineEdit-Field. - */ -void OpenMoCapDialog::setFileName(){ - std::stringstream extensionsString; - extensionsString << "All MoCap File Types ("; - for(const auto &extension: moCapFileExtensions){ - extensionsString << " *." << extension.second; - } - extensionsString << ")"; - QString filename = QFileDialog::getOpenFileName(this, tr("Open C3D File"), QDir::currentPath(), - QString::fromStdString(extensionsString.str())); - mUi->filePathLineEdit->clear(); - mUi->filePathLineEdit->insert(filename); - mUi->pushButtonOK->setDisabled(filename.isEmpty()); -} /** * @brief Sets FileAttributes of MoCapController and calls readMoCapFile @@ -77,20 +57,39 @@ void OpenMoCapDialog::setFileName(){ * This method is called by a Signal(Ok-Button) and closes the window if no errors occur. */ void OpenMoCapDialog::clickedOk() { - QString filePath = mUi->filePathLineEdit->text(); - int samplerate = mUi->sampleRateSpinBox->value(); - double offset = mUi->offSetSpinBox->value(); - MoCapSystem system = mMoCapSystems.value(mUi->cbInputSystem->currentText()); - std::stringstream errormsg; - try{ - std::vector<MoCapPersonMetadata> metadata; - MoCapPersonMetadata currentMetadata(filePath.toStdString(), system, samplerate, offset); - metadata.push_back(currentMetadata); - mController.readMoCapFiles(metadata); - this->close(); - }catch(std::exception &e){ - errormsg << e.what() << "\n"; - QMessageBox::critical(mParent, "PeTrack", QString::fromStdString(errormsg.str())); + bool allDataIsValid = true; + std::vector<MoCapPersonMetadata> metadata; + + for(int i = 0; i < mUi->moCapSelections->layout()->count(); ++i) + { + auto selectionWidget = dynamic_cast<const MoCapSelectionWidget*>(mUi->moCapSelections->layout()->itemAt(i)->widget()); + if(selectionWidget == nullptr || !selectionWidget->isFilledOut()) + { + continue; + } + + try{ + MoCapPersonMetadata currentMetadata = selectionWidget->getMetadata(); + metadata.push_back(currentMetadata); + }catch(std::exception &e){ + allDataIsValid = false; + std::stringstream errormsg; + errormsg << e.what() << "\n"; + QMessageBox::critical(mParent, "PeTrack", QString::fromStdString(errormsg.str())); + } + } + + + if(allDataIsValid) + { + try { + mController.readMoCapFiles(metadata); + this->close(); + } catch (std::exception &e) { + std::stringstream errormsg; + errormsg << e.what() << "\n"; + QMessageBox::critical(mParent, "PeTrack", QString::fromStdString(errormsg.str())); + } } } @@ -99,3 +98,9 @@ OpenMoCapDialog::~OpenMoCapDialog() { delete mUi; } + +void OpenMoCapDialog::on_btnAddSelection_clicked() +{ + mUi->moCapSelections->layout()->addWidget(new MoCapSelectionWidget(this, mMoCapSystems)); +} + diff --git a/src/petrack.cpp b/src/petrack.cpp index 3c82cb828..f9fffaf8f 100644 --- a/src/petrack.cpp +++ b/src/petrack.cpp @@ -52,6 +52,8 @@ #include "pMessageBox.h" #include "trackingRoiItem.h" #include "recognitionRoiItem.h" +#include "openMoCapDialog.h" + #include "aboutDialog.h" #ifdef AVI @@ -1445,7 +1447,7 @@ void Petrack::createActions() //mOpenCameraAct->setShortcut(tr("Ctrl+C")); // because of some reason it is sometimes fired with Ctrl+LeftMouseButton ==> so disabled (it's also not really needed) connect(mOpenCameraAct, SIGNAL(triggered()), this, SLOT(openCameraLiveStream())); - mOpenMoCapAct = new QAction(tr("Open MoCap File"), this); + mOpenMoCapAct = new QAction(tr("Manage MoCap Files"), this); connect(mOpenMoCapAct, &QAction::triggered, this, &Petrack::openMoCapFile); mSaveSeqVidAct = new QAction(tr("Save Video"), this); diff --git a/ui/moCapSelectionWidget.ui b/ui/moCapSelectionWidget.ui new file mode 100644 index 000000000..d12968d8b --- /dev/null +++ b/ui/moCapSelectionWidget.ui @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MoCapSelectionWidget</class> + <widget class="QWidget" name="MoCapSelectionWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>544</width> + <height>71</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,1,0"> + <item> + <widget class="QPushButton" name="browseFileButton"> + <property name="text"> + <string>Browse File</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="filePathLabel"> + <property name="text"> + <string>File</string> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="btnDelete"> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Offset(sec):</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QDoubleSpinBox" name="offSetSpinBox"/> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Samplerate(Hz):</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QDoubleSpinBox" name="sampleRateSpinBox"/> + </item> + <item> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>System:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="cbInputSystem"/> + </item> + </layout> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/ui/openMoCapDialog.ui b/ui/openMoCapDialog.ui index c1cc55a1f..30f49ef15 100644 --- a/ui/openMoCapDialog.ui +++ b/ui/openMoCapDialog.ui @@ -6,73 +6,100 @@ <rect> <x>0</x> <y>0</y> - <width>258</width> - <height>150</height> + <width>529</width> + <height>151</height> </rect> </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="windowTitle"> <string>Dialog</string> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <layout class="QGridLayout" name="gridLayout"> - <property name="horizontalSpacing"> - <number>6</number> + <widget class="QScrollArea" name="scrollArea"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> - <item row="1" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Offset (seconds)</string> - </property> - </widget> - </item> - <item row="3" column="2"> - <widget class="QLineEdit" name="filePathLineEdit"/> - </item> - <item row="4" column="2"> - <widget class="QComboBox" name="cbInputSystem"/> - </item> - <item row="1" column="2"> - <widget class="QDoubleSpinBox" name="offSetSpinBox"/> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Input System</string> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAsNeeded</enum> + </property> + <property name="sizeAdjustPolicy"> + <enum>QAbstractScrollArea::AdjustToContents</enum> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <widget class="QWidget" name="moCapSelections"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>509</width> + <height>69</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label"> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="btnAddSelection"> <property name="text"> - <string>Samplerate (Hz)</string> + <string>+</string> </property> </widget> </item> - <item row="0" column="2"> - <widget class="QSpinBox" name="sampleRateSpinBox"/> - </item> - <item row="5" column="0"> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> <widget class="QPushButton" name="pushButtonCancel"> <property name="text"> <string>Cancel</string> </property> </widget> </item> - <item row="5" column="2"> + <item> <widget class="QPushButton" name="pushButtonOK"> <property name="text"> <string>OK</string> </property> </widget> </item> - <item row="3" column="0"> - <widget class="QPushButton" name="browseFileButton"> - <property name="text"> - <string>Browse MoCap-File</string> - </property> - </widget> - </item> </layout> </item> </layout> -- GitLab