aboutsummaryrefslogtreecommitdiff
path: root/src/labeller.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/labeller.cc')
-rw-r--r--src/labeller.cc116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/labeller.cc b/src/labeller.cc
new file mode 100644
index 0000000..64da2d7
--- /dev/null
+++ b/src/labeller.cc
@@ -0,0 +1,116 @@
+#include "labeller.h"
+#include "settings.h"
+#include <fstream>
+
+
+namespace backend {
+ struct labeller_impl {
+ std::vector<std::string> labels;
+ std::vector<label> annotations;
+ // Bool in undo/redo buffers is whether was applied or deleted
+ std::vector<std::pair<bool, label>> undoBuffer;
+ std::vector<std::pair<bool, label>> redoBuffer;
+ std::filesystem::path savepath;
+ };
+
+ labeller::labeller(const std::filesystem::path& savepath) {
+ data = std::shared_ptr<labeller_impl>(new labeller_impl);
+ data->labels = settings::getLabels();
+ data->savepath = savepath;
+ }
+
+ std::pair<label, label> labeller::getSurrounding(double time) const {
+ std::pair<label, label> labs;
+ if(!data->annotations.empty()) {
+ auto above = data->annotations.rbegin();
+ auto below = above;
+ auto rit = above;
+ while(++rit != data->annotations.rend()) {
+ if(rit->time > time && (above->time <= time || rit->time < above->time)) above = rit;
+ if(rit->time <= time && (below->time > time || rit->time > below->time)) below = rit;
+ }
+ if(below->time <= time) labs.first = *below;
+ if(above->time > time) labs.second = *above;
+ }
+ return labs;
+ }
+
+ std::vector<std::string> labeller::getLabels() const {
+ return data->labels;
+ }
+
+ void appLab(std::vector<label>& annotations, label lab) {
+ annotations.push_back(lab);
+ }
+
+ void labeller::applyLabel(std::string name, double time) {
+ label lab(name, time);
+ appLab(data->annotations, lab);
+ data->undoBuffer.push_back({true, lab});
+ data->redoBuffer.clear();
+ }
+
+ double abs(double x) {
+ if(x < 0) x *= -1;
+ return x;
+ }
+
+ label delLab(std::vector<label>& annotations, double time) {
+ if(annotations.empty()) {
+ return label();
+ }
+ auto closest = annotations.rbegin();
+ auto rit = closest;
+ while(++rit != annotations.rend()) {
+ if(abs(rit->time - time) < abs(closest->time - time)) {
+ closest = rit;
+ }
+ }
+ label c(*closest);
+ annotations.erase(closest.base());
+ return c;
+ }
+
+ void labeller::deleteLabel(double time) {
+ label deleted = delLab(data->annotations, time);
+ data->undoBuffer.push_back({false, deleted});
+ data->redoBuffer.clear();
+ }
+
+ // Pops action from 'from', applies, and appends to 'to'.
+ void handleUndoRedo(std::vector<std::pair<bool, label>>& from, std::vector<std::pair<bool, label>>& to, std::vector<label>& annotations) {
+ if(! from.empty()) {
+ auto elem = from.back();
+ from.pop_back();
+ if(elem.first) { // It was applied, so we must unapply
+ delLab(annotations, elem.second.time);
+ } else {
+ appLab(annotations, elem.second);
+ }
+ to.push_back({! elem.first, elem.second});
+ }
+ }
+
+ void labeller::undo() {
+ handleUndoRedo(data->undoBuffer, data->redoBuffer, data->annotations);
+ }
+
+ void labeller::redo() {
+ handleUndoRedo(data->redoBuffer, data->undoBuffer, data->annotations);
+ }
+
+ bool compareLabels(label l1, label l2) {
+ return (l1.time < l2.time);
+ }
+
+ void labeller::save() const {
+ std::ofstream out;
+ out.open(data->savepath);
+ std::vector<label> a(data->annotations);
+ std::sort(a.begin(), a.end(), compareLabels);
+ for(label l : a) {
+ out << l.name << "," << l.time << std::endl;
+ }
+ out.close();
+ }
+}