diff --git a/include/moCapPerson.h b/include/moCapPerson.h index 0158743e2e688158a2e463e1a330d7b708f47126..ec081ada908285c9e0e278a8a7b7702d13419c50 100644 --- a/include/moCapPerson.h +++ b/include/moCapPerson.h @@ -44,7 +44,8 @@ public: inline const SkeletonTree &getSample(size_t sample) const { return mSkeletons.at(sample); } void setSamplerate(double samplerate); - void setTimeOffset(double timeOffset); + void setUserTimeOffset(double timeOffset); + void setFileTimeOffset(double timeOffset); void setMetadata(const MoCapPersonMetadata &metadata); void addSkeleton(const SkeletonTree &skeleton); const SkeletonTree & getSkeleton(size_t samples) const; diff --git a/include/moCapPersonMetadata.h b/include/moCapPersonMetadata.h index 0f49230ad4b0dea28b840bf8ed26e2f409511078..8d792f01f71ccf16eca89783baafb82921c60097 100644 --- a/include/moCapPersonMetadata.h +++ b/include/moCapPersonMetadata.h @@ -49,24 +49,39 @@ public: MoCapPersonMetadata &operator=(const MoCapPersonMetadata &) = default; MoCapPersonMetadata &operator=(MoCapPersonMetadata &&) = default; ~MoCapPersonMetadata() = default; - MoCapPersonMetadata(std::string filepath, MoCapSystem system, double samplerate, double offset); + MoCapPersonMetadata( + std::string filepath, + MoCapSystem system, + double samplerate, + double userTimeOffset, + double fileTimeOffset); - void setFilepath(const std::string &filepath, MoCapSystem system); - void setSamplerate(double samplerate); - void setOffset(double offset); - void setMetadata(const std::string &filepath, MoCapSystem, double samplerate, double offset); + void setFilepath(const std::string &filepath, MoCapSystem system); + void setSamplerate(double samplerate); + void setUserTimeOffset(double offset); + void setFileTimeOffset(double offset); + void setMetadata( + const std::string &filepath, + MoCapSystem, + double samplerate, + double userTimeOffset, + double fileTimeOffset); MoCapSystem getSystem() const; double getSamplerate() const; double getOffset() const; + double getUserTimeOffset() const; const std::string &getFilepath() const; private: - std::string mFilepath = ""; - MoCapSystem mSystem = XSensC3D; - double mSamplerate = 60; - double mOffset = 0; ///< time offset from MoCap to video in seconds + std::string mFilepath = ""; + MoCapSystem mSystem = XSensC3D; + double mSamplerate = 60; + double mUserTimeOffset = 0; ///< user chosen time offset from MoCap to video in seconds + double mFileTimeOffset = 0; ///< time offset in seconds not from user but from MoCap-file }; +bool readsTheSame(const MoCapPersonMetadata &lhs, const MoCapPersonMetadata &rhs); + bool operator==(const MoCapPersonMetadata &lhs, const MoCapPersonMetadata &rhs); bool operator!=(const MoCapPersonMetadata &lhs, const MoCapPersonMetadata &rhs); #endif // MOCAPPERSONMETADATA_H diff --git a/src/IO.cpp b/src/IO.cpp index 9cbd9756a5e1db215f73857d5eee4443e9528abf..74e894404ce8892ce8e4f3c0e3adbc5f5b04fa86 100644 --- a/src/IO.cpp +++ b/src/IO.cpp @@ -160,7 +160,7 @@ void IO::readMoCapC3D(MoCapStorage &storage, const MoCapPersonMetadata &metadata } size_t firstFrame = c3d.header().firstFrame(); - person.setTimeOffset(person.getMetadata().getOffset() - firstFrame / person.getMetadata().getSamplerate()); + person.setFileTimeOffset(-static_cast<double>(firstFrame) / person.getMetadata().getSamplerate()); // getImagePoint takes points in cm -> cm as target unit const std::string unit = c3d.parameters().group("POINT").parameter("UNITS").valuesAsString()[0]; diff --git a/src/moCapController.cpp b/src/moCapController.cpp index d4405f4e8ee1a90b86715d3c3c0f516e1ea4aceb..447dde4169bd1bca2ee2f1a185dbabd9bf61ac1f 100644 --- a/src/moCapController.cpp +++ b/src/moCapController.cpp @@ -251,13 +251,21 @@ std::vector<MoCapPersonMetadata> MoCapController::getAllMoCapPersonMetadata() co void MoCapController::readMoCapFiles(const std::vector<MoCapPersonMetadata> &newMetadata) { std::vector<MoCapPerson> &persons = mStorage.getPersons(); - auto unselected = [&](auto person) - { return std::find(newMetadata.cbegin(), newMetadata.cend(), person.getMetadata()) == newMetadata.cend(); }; + auto unselected = [&](MoCapPerson person) + { + return std::find_if( + newMetadata.cbegin(), + newMetadata.cend(), + [&person](const MoCapPersonMetadata &other) + { return readsTheSame(other, person.getMetadata()); }) == newMetadata.cend(); + }; persons.erase(std::remove_if(persons.begin(), persons.end(), unselected), persons.end()); std::vector<MoCapPersonMetadata> currentMetadata = getAllMoCapPersonMetadata(); for(const MoCapPersonMetadata &md : newMetadata) { - bool isNewMd = std::find(currentMetadata.cbegin(), currentMetadata.cend(), md) == currentMetadata.cend(); + const auto isCurrentMD = [&md](const MoCapPersonMetadata &lhs) { return readsTheSame(lhs, md); }; + bool isNewMd = + std::find_if(currentMetadata.cbegin(), currentMetadata.cend(), isCurrentMD) == currentMetadata.cend(); if(isNewMd) { IO::readMoCapC3D(mStorage, md); @@ -358,7 +366,7 @@ void MoCapController::getXml(const QDomElement &elem) } if(subElem.hasAttribute("TIME_OFFSET")) { - metadata.setOffset(subElem.attribute("TIME_OFFSET").toDouble(&ok)); + metadata.setUserTimeOffset(subElem.attribute("TIME_OFFSET").toDouble(&ok)); std::stringstream ss; ss << "Element TIME_OFFSET of file " << path << " does not contain a valid floating-point number!"; if(!ok) diff --git a/src/moCapPerson.cpp b/src/moCapPerson.cpp index aac5c527c0552f54342527c362415ade4bf9fb44..e63d76d1933bf65e0eba05a39dd6aab3c6970bb1 100644 --- a/src/moCapPerson.cpp +++ b/src/moCapPerson.cpp @@ -41,9 +41,14 @@ void MoCapPerson::setSamplerate(double samplerate) mMetadata.setSamplerate(samplerate); } -void MoCapPerson::setTimeOffset(double timeOffset) +void MoCapPerson::setUserTimeOffset(double timeOffset) { - mMetadata.setOffset(timeOffset); + mMetadata.setUserTimeOffset(timeOffset); +} + +void MoCapPerson::setFileTimeOffset(double timeOffset) +{ + mMetadata.setFileTimeOffset(timeOffset); } void MoCapPerson::addSkeleton(const SkeletonTree &skeleton) @@ -78,7 +83,7 @@ void MoCapPerson::setXml(QDomElement &elem) const subElem = elem.ownerDocument().createElement("PERSON"); elem.appendChild(subElem); - subElem.setAttribute("TIME_OFFSET", mMetadata.getOffset()); + subElem.setAttribute("TIME_OFFSET", mMetadata.getUserTimeOffset()); subElem.setAttribute("FILE", getFileList(QString::fromStdString(mMetadata.getFilepath()))); subElem.setAttribute("SAMPLE_RATE", mMetadata.getSamplerate()); subElem.setAttribute("SYSTEM", mMetadata.getSystem()); diff --git a/src/moCapPersonMetadata.cpp b/src/moCapPersonMetadata.cpp index 0434c6559f666727cb3739bf02dd1aa3ba802c9e..eda3d1e69bad3193415b9cef1181227200994730 100644 --- a/src/moCapPersonMetadata.cpp +++ b/src/moCapPersonMetadata.cpp @@ -21,16 +21,27 @@ #include <QFileInfo> -MoCapPersonMetadata::MoCapPersonMetadata(std::string filepath, MoCapSystem system, double samplerate, double offset) +MoCapPersonMetadata::MoCapPersonMetadata( + std::string filepath, + MoCapSystem system, + double samplerate, + double userTimeOffset, + double fileTimeOffset) { - setMetadata(filepath, system, samplerate, offset); + setMetadata(filepath, system, samplerate, userTimeOffset, fileTimeOffset); } -void MoCapPersonMetadata::setMetadata(const std::string &filepath, MoCapSystem system, double samplerate, double offset) +void MoCapPersonMetadata::setMetadata( + const std::string &filepath, + MoCapSystem system, + double samplerate, + double userTimeOffset, + double fileTimeOffset) { setSamplerate(samplerate); - setOffset(offset); + setUserTimeOffset(userTimeOffset); + setFileTimeOffset(fileTimeOffset); setFilepath(filepath, system); } @@ -71,9 +82,14 @@ void MoCapPersonMetadata::setSamplerate(double samplerate) mSamplerate = samplerate; } -void MoCapPersonMetadata::setOffset(double offset) +void MoCapPersonMetadata::setUserTimeOffset(double offset) { - mOffset = offset; + mUserTimeOffset = offset; +} + +void MoCapPersonMetadata::setFileTimeOffset(double offset) +{ + mFileTimeOffset = offset; } const std::string &MoCapPersonMetadata::getFilepath() const @@ -93,7 +109,12 @@ double MoCapPersonMetadata::getSamplerate() const double MoCapPersonMetadata::getOffset() const { - return mOffset; + return mUserTimeOffset + mFileTimeOffset; +} + +double MoCapPersonMetadata::getUserTimeOffset() const +{ + return mUserTimeOffset; } bool operator==(const MoCapPersonMetadata &lhs, const MoCapPersonMetadata &rhs) @@ -107,3 +128,23 @@ bool operator!=(const MoCapPersonMetadata &lhs, const MoCapPersonMetadata &rhs) { return !(lhs == rhs); } + +/** + * @brief Indicates if both metadata result in the same Person after reading + * + * This function indicated whether the two given metadata would result in the + * same person after calling IO::readMoCapC3D (or other) with them. That could be + * the case, if everything is the same except the file offset, which is newly set + * anyways. + * + * @param lhs first metadata + * @param rhs second metadata + * @return true if both result in same person after reading + */ +bool readsTheSame(const MoCapPersonMetadata &lhs, const MoCapPersonMetadata &rhs) +{ + return ( + lhs.getFilepath().compare(rhs.getFilepath()) == 0 && + std::abs(lhs.getUserTimeOffset() - rhs.getUserTimeOffset()) < 1e-4 && + std::abs(lhs.getSamplerate() - rhs.getSamplerate()) < 1e-4 && lhs.getSystem() == rhs.getSystem()); +} diff --git a/src/moCapSelectionWidget.cpp b/src/moCapSelectionWidget.cpp index 689928adda20e2cec9bdcaab939d34049945c17b..ee339ffab3c288897f72001519dc6c81e0e4ff1b 100644 --- a/src/moCapSelectionWidget.cpp +++ b/src/moCapSelectionWidget.cpp @@ -11,7 +11,7 @@ MoCapSelectionWidget::MoCapSelectionWidget(QWidget *parent, const QMap<QString, mUi->setupUi(this); constexpr int defaultSampleRate = 60; - constexpr double offsetRange = 5; + constexpr double offsetRange = 999'999; mUi->btnDelete->setIcon(QApplication::style()->standardIcon(QStyle::SP_TrashIcon)); mUi->cbInputSystem->addItems(QStringList(moCapSystems.keys())); @@ -43,7 +43,7 @@ MoCapSelectionWidget::MoCapSelectionWidget( mUi->cbInputSystem->setCurrentText(usedMoCapSystem.key()); } mUi->sampleRateSpinBox->setValue(metadata.getSamplerate()); - mUi->offSetSpinBox->setValue(metadata.getOffset()); + mUi->offSetSpinBox->setValue(metadata.getUserTimeOffset()); mUi->filePathLabel->setText(QString::fromStdString(metadata.getFilepath())); mFilledOut = true; } @@ -101,7 +101,8 @@ MoCapPersonMetadata MoCapSelectionWidget::getMetadata() const mUi->filePathLabel->text().toStdString(), mMoCapSystems[mUi->cbInputSystem->currentText()], mUi->sampleRateSpinBox->value(), - mUi->offSetSpinBox->value()); + mUi->offSetSpinBox->value(), + 0); } bool MoCapSelectionWidget::isFilledOut() const diff --git a/tests/unit_test/tst_moCapController.cpp b/tests/unit_test/tst_moCapController.cpp index 956d0c58838a931525bdb0efcb5f684cd344ee7c..602ddc7848455357fb36509e8bb06c632e7bf39e 100644 --- a/tests/unit_test/tst_moCapController.cpp +++ b/tests/unit_test/tst_moCapController.cpp @@ -54,7 +54,7 @@ SCENARIO("I want to get the render data with one person loaded", "[ui]") MoCapPerson person; person.setSamplerate(1); - person.setTimeOffset(0); + // default time offset 0 ExtrCalibMock extrCalib;