From c4a421dcaaf41d3c61f8722f565709eaa18a3ee8 Mon Sep 17 00:00:00 2001 From: "Kilic, Deniz" <d.kilic@fz-juelich.de> Date: Thu, 18 Nov 2021 15:21:47 +0100 Subject: [PATCH] Add simple AutoSave capability for TRC files --- include/personStorage.h | 5 +- include/petrack.h | 9 +- src/autosave.cpp | 108 ++++++++++++++++++++++++ src/personStorage.cpp | 24 ++++++ src/petrack.cpp | 12 +++ tests/unit_test/tst_moCapController.cpp | 3 +- 6 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 src/autosave.cpp diff --git a/include/personStorage.h b/include/personStorage.h index 352489a23..f7ff02a20 100644 --- a/include/personStorage.h +++ b/include/personStorage.h @@ -26,7 +26,7 @@ #include <vector> class Petrack; - +class Autosave; class PersonStorage { @@ -38,7 +38,7 @@ public: Whole }; - explicit PersonStorage(Petrack &mainWindow) : mMainWindow(mainWindow) {} + explicit PersonStorage(Petrack &mainWindow, Autosave &autosave) : mMainWindow(mainWindow), mAutosave(autosave) {} void splitPerson(size_t pers, int frame); bool splitPersonAt(const Vec2F &p, int frame, const QSet<int> &onlyVisible); @@ -121,6 +121,7 @@ public: private: std::vector<TrackPerson> mPersons; Petrack & mMainWindow; + Autosave & mAutosave; }; #endif // PERSONSTORAGE_H diff --git a/include/petrack.h b/include/petrack.h index 36bdcef31..2add0cb9c 100644 --- a/include/petrack.h +++ b/include/petrack.h @@ -32,6 +32,7 @@ #include "stereoContext.h" #endif #include "autoCalib.h" +#include "autosave.h" #include "backgroundFilter.h" #include "borderFilter.h" #include "brightContrastFilter.h" @@ -458,14 +459,15 @@ private: reco::Recognizer mReco; - PersonStorage mPersonStorage{*this}; + QDomDocument mDefaultSettings; + Autosave mAutosave{*this}; + + PersonStorage mPersonStorage{*this, mAutosave}; Tracker * mTracker; TrackerReal * mTrackerReal; double mHeadSize; double mCmPerPixel; - QDomDocument mDefaultSettings; - double mShowFPS; bool mAutoBackTrack; @@ -475,7 +477,6 @@ private: MoCapStorage mStorage; MoCapController mMoCapController{mStorage, mExtrCalibration}; - QString mPetrackVersion{"Unknown"}; ///< Version of PeTrack used to compile QString mGitCommitID{"Unknown"}; ///< Commit hash used to compile QString mGitCommitDate{"Unknown"}; ///< Commit date used to compile diff --git a/src/autosave.cpp b/src/autosave.cpp new file mode 100644 index 000000000..c3c1f5ff4 --- /dev/null +++ b/src/autosave.cpp @@ -0,0 +1,108 @@ +#include "autosave.h" + +#include "petrack.h" + + +void Autosave::trackPersonModified() +{ + mChangeCounter++; + constexpr int changesTillAutosave = 10; + if(mChangeCounter >= changesTillAutosave) + { + mChangeCounter = 0; + saveTrc(); + } +} + +bool Autosave::checkAutosave() +{ + return !getAutosave().empty(); +} + +void Autosave::deleteAutosave() +{ + auto autosaves = getAutosave(); + if(!autosaves.empty()) + { + for(auto &save : autosaves) + { + QFile saveFile{save}; + saveFile.remove(); + } + } +} + +void Autosave::loadAutosave() +{ + auto autosaveFiles = getAutosave(); + if(autosaveFiles.empty()) + { + return; + } + + QString autosaveFilename = autosaveFiles[0]; + auto trcFile = mPetrack.getTrackFileName(); + mPetrack.importTracker(autosaveFilename); + mPetrack.setTrackFileName(trcFile); +} + +QString Autosave::buildAutosaveName(const QString &projectFileName, bool temp) +{ + QFileInfo projectFile{projectFileName}; + if(temp) + { + return projectFile.dir().filePath("." + projectFile.baseName() + "_autosave_running.trc"); + } + + return projectFile.dir().filePath("." + projectFile.baseName() + "_autosave.trc"); +} + +void Autosave::savePet() {} + +void Autosave::saveTrc() +{ + auto projectName = mPetrack.getProFileName(); + QString autosaveName = buildAutosaveName(projectName, true); + auto trackFileName = mPetrack.getTrackFileName(); + mPetrack.exportTracker(autosaveName); + mPetrack.setTrackFileName(trackFileName); + + QString finalAutosaveName = buildAutosaveName(projectName); + QFile tempAutosave{autosaveName}; + QFile autosave{finalAutosaveName}; + if(tempAutosave.exists()) + { + if(autosave.exists()) + { + autosave.remove(); + } + if(tempAutosave.copy(finalAutosaveName)) + { + // we don't currently use it for loading, so we could remove it even if the copying fails... + tempAutosave.remove(); + } + } +} + +QStringList Autosave::getAutosave() +{ + auto projectPath = QFileInfo(mPetrack.getProFileName()); + if(projectPath.isDir()) + { + auto children = projectPath.dir().entryList(); + auto autosaveFiles = children.filter(QRegularExpression(R"(\..*_autosave.trc)")); + return autosaveFiles; + } + + if(projectPath.isFile()) + { + auto autosaveName = buildAutosaveName(projectPath.absoluteFilePath()); + QFileInfo autosave{autosaveName}; + if(autosave.exists()) + { + return QStringList{autosaveName}; + } + } + + return QStringList{}; +} diff --git a/src/personStorage.cpp b/src/personStorage.cpp index 1bc6d97ea..b428e2b4b 100644 --- a/src/personStorage.cpp +++ b/src/personStorage.cpp @@ -21,6 +21,7 @@ #include "personStorage.h" #include "animation.h" +#include "autosave.h" #include "control.h" #include "multiColorMarkerWidget.h" #include "pMessageBox.h" @@ -34,6 +35,7 @@ */ void PersonStorage::splitPerson(size_t pers, int frame) { + mAutosave.trackPersonModified(); int j; if(mPersons.at(pers).firstFrame() < frame) @@ -66,6 +68,7 @@ void PersonStorage::splitPerson(size_t pers, int frame) */ bool PersonStorage::splitPersonAt(const Vec2F &point, int frame, const QSet<int> &onlyVisible) { + mAutosave.trackPersonModified(); for(size_t i = 0; i < mPersons.size(); ++i) { // ueber TrackPerson if(((onlyVisible.empty()) || (onlyVisible.contains(i))) && @@ -90,6 +93,7 @@ bool PersonStorage::splitPersonAt(const Vec2F &point, int frame, const QSet<int> */ bool PersonStorage::delPointOf(int pers, int direction, int frame) { + mAutosave.trackPersonModified(); if(direction == -1) { for(int j = 0; j < frame - mPersons.at(pers).firstFrame(); ++j) @@ -125,6 +129,7 @@ bool PersonStorage::delPointOf(int pers, int direction, int frame) */ bool PersonStorage::delPoint(const Vec2F &point, int direction, int frame, const QSet<int> &onlyVisible) { + mAutosave.trackPersonModified(); for(int i = 0; i < static_cast<int>(mPersons.size()); ++i) { // ueber TrackPerson if(((onlyVisible.empty()) || (onlyVisible.contains(i))) && @@ -146,6 +151,7 @@ bool PersonStorage::delPoint(const Vec2F &point, int direction, int frame, const */ void PersonStorage::delPointAll(Direction direction, int frame) { + mAutosave.trackPersonModified(); for(size_t i = 0; i < mPersons.size(); ++i) // ueber TrackPerson { if(mPersons.at(i).trackPointExist(frame)) @@ -190,6 +196,7 @@ void PersonStorage::delPointAll(Direction direction, int frame) */ void PersonStorage::delPointInsideROI() { + mAutosave.trackPersonModified(); QRectF rect = mMainWindow.getRecoRoiItem()->rect(); bool inside; @@ -225,6 +232,7 @@ void PersonStorage::delPointInsideROI() */ void PersonStorage::delPointROI() { + mAutosave.trackPersonModified(); int anz = 0; QRectF rect = mMainWindow.getRecoRoiItem()->rect(); @@ -258,6 +266,7 @@ void PersonStorage::delPointROI() */ bool PersonStorage::editTrackPersonComment(const Vec2F &point, int frame, const QSet<int> &onlyVisible) { + mAutosave.trackPersonModified(); for(int i = 0; i < static_cast<int>(mPersons.size()); ++i) // ueber TrackPerson { if(((onlyVisible.empty()) || (onlyVisible.contains(i))) && @@ -312,6 +321,7 @@ bool PersonStorage::editTrackPersonComment(const Vec2F &point, int frame, const */ bool PersonStorage::setTrackPersonHeight(const Vec2F &point, int frame, const QSet<int> &onlyVisible) { + mAutosave.trackPersonModified(); for(int i = 0; i < static_cast<int>(mPersons.size()); ++i) // ueber TrackPerson { if(((onlyVisible.empty()) || (onlyVisible.contains(i))) && @@ -379,6 +389,7 @@ bool PersonStorage::setTrackPersonHeight(const Vec2F &point, int frame, const QS */ bool PersonStorage::resetTrackPersonHeight(const Vec2F &point, int frame, QSet<int> onlyVisible) { + mAutosave.trackPersonModified(); for(int i = 0; i < static_cast<int>(mPersons.size()); ++i) // ueber TrackPerson { if(((onlyVisible.empty()) || (onlyVisible.contains(i))) && @@ -472,6 +483,11 @@ bool PersonStorage::addPoint( reco::RecognitionMethod method, int * pers) { + if(point.qual() > 100) + { + // manually added point + mAutosave.trackPersonModified(); + } bool found = false; int i, iNearest = 0.; float scaleHead; @@ -682,6 +698,7 @@ int PersonStorage::smallestFirstFrame() const */ void PersonStorage::recalcHeight(float altitude) { + mAutosave.trackPersonModified(); for(auto &person : mPersons) { person.recalcHeight(altitude); @@ -894,6 +911,7 @@ void PersonStorage::checkPlausibility( /// optimize color for all persons void PersonStorage::optimizeColor() { + mAutosave.trackPersonModified(); for(auto &person : mPersons) { if(person.color().isValid()) @@ -906,6 +924,7 @@ void PersonStorage::optimizeColor() /// reset the height of all persons, but not the pos of the trackpoints void PersonStorage::resetHeight() { + mAutosave.trackPersonModified(); for(auto &person : mPersons) { person.resetHeight(); @@ -915,6 +934,7 @@ void PersonStorage::resetHeight() /// reset the pos of the tzrackpoints, but not the heights void PersonStorage::resetPos() { + mAutosave.trackPersonModified(); for(auto &person : mPersons) { for(auto &point : person) @@ -985,6 +1005,7 @@ bool PersonStorage::printHeightDistribution() */ void PersonStorage::setMarkerHeights(const std::unordered_map<int, float> &heights) { + mAutosave.trackPersonModified(); for(auto &person : mPersons) // over TrackPerson { for(auto &point : person) // over TrackPoints @@ -1017,6 +1038,7 @@ void PersonStorage::setMarkerHeights(const std::unordered_map<int, float> &heigh */ void PersonStorage::setMarkerIDs(const std::unordered_map<int, int> &markerIDs) { + mAutosave.trackPersonModified(); for(int i = 0; i < static_cast<int>(mPersons.size()); ++i) // over TrackPerson { // personID of current person @@ -1050,6 +1072,7 @@ void PersonStorage::setMarkerIDs(const std::unordered_map<int, int> &markerIDs) */ void PersonStorage::purge(int frame) { + mAutosave.trackPersonModified(); int i, j; float count; ///< number of trackpoints without recognition @@ -1177,6 +1200,7 @@ void PersonStorage::insertFeaturePoint( */ int PersonStorage::merge(int pers1, int pers2) { + mAutosave.trackPersonModified(); auto & person = mPersons.at(pers1); auto & other = mPersons.at(pers2); const bool extrapolate = mMainWindow.getControlWidget()->trackExtrapolation->checkState() == Qt::Checked; diff --git a/src/petrack.cpp b/src/petrack.cpp index ed3ae0850..d6fb82e92 100644 --- a/src/petrack.cpp +++ b/src/petrack.cpp @@ -593,6 +593,7 @@ void Petrack::openProject(QString fileName, bool openSeq) // default fileName="" { return; } + mAutosave.deleteAutosave(); } // if no destination file or folder is given if(fileName.isEmpty()) @@ -649,6 +650,16 @@ void Petrack::openProject(QString fileName, bool openSeq) // default fileName="" mControlWidget->setNewModelChecked(false); } updateWindowTitle(); + + if(mAutosave.checkAutosave()) + { + auto ret = + PQuestion(this, "Autosave detected", "An autosave was detected.\nDo you want to load the Autosave?"); + if(ret == PMessageBox::StandardButton::Yes) + { + mAutosave.loadAutosave(); + } + } } } @@ -2526,6 +2537,7 @@ void Petrack::closeEvent(QCloseEvent *event) if(maybeSave()) { writeSettings(); + mAutosave.deleteAutosave(); event->accept(); } else diff --git a/tests/unit_test/tst_moCapController.cpp b/tests/unit_test/tst_moCapController.cpp index 1e8591e6f..c26580c51 100644 --- a/tests/unit_test/tst_moCapController.cpp +++ b/tests/unit_test/tst_moCapController.cpp @@ -60,7 +60,8 @@ SCENARIO("I want to get the render data with one person loaded", "[ui]") // default time offset 0 Petrack pet; - PersonStorage st{pet}; + Autosave save{pet}; + PersonStorage st{pet, save}; ExtrCalibMock extrCalib{st}; /* -- GitLab