diff options
author | Your Name <you@example.com> | 2021-05-13 17:20:26 -0400 |
---|---|---|
committer | Your Name <you@example.com> | 2021-05-13 17:20:26 -0400 |
commit | 5a6248518654ec97d95d2c463e3ffb4be7bbf456 (patch) | |
tree | a6ebb6bb26ba2a6b4abc3829a81c58ae97fd2e05 /src/labeller.cc | |
download | annotator-5a6248518654ec97d95d2c463e3ffb4be7bbf456.tar.gz annotator-5a6248518654ec97d95d2c463e3ffb4be7bbf456.tar.bz2 annotator-5a6248518654ec97d95d2c463e3ffb4be7bbf456.zip |
Initial commit
Diffstat (limited to 'src/labeller.cc')
-rw-r--r-- | src/labeller.cc | 116 |
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(); + } +} |