From 5bd1fec462466d605f974fa27c3b00826a1bab57 Mon Sep 17 00:00:00 2001 From: Samuel Fadel Date: Fri, 12 Feb 2016 19:03:51 -0200 Subject: Refactoring of Projection{Observer,History} & ManipulationHandler. ProjectionObserver class has been removed, all of its functionality is now inside class ProjectionHistory, thus dealing with the design problem mentioned in the previous commit. ProjectionHistory is now also responsible for all rewinding functionality, which makes more sense. --- main.cpp | 49 ++++------- main.h | 51 +++++------- manipulationhandler.cpp | 10 --- manipulationhandler.h | 2 - pm.pro | 2 - projectionhistory.cpp | 191 +++++++++++++++++++++++++++++++++++++++++-- projectionhistory.h | 54 +++++++++++-- projectionobserver.cpp | 210 ------------------------------------------------ projectionobserver.h | 61 -------------- 9 files changed, 270 insertions(+), 360 deletions(-) delete mode 100644 projectionobserver.cpp delete mode 100644 projectionobserver.h diff --git a/main.cpp b/main.cpp index a5aaf68..407753c 100644 --- a/main.cpp +++ b/main.cpp @@ -17,11 +17,11 @@ #include "barchart.h" #include "colormap.h" #include "transitioncontrol.h" +#include "projectionhistory.h" #include "manipulationhandler.h" #include "mapscalehandler.h" #include "selectionhandler.h" #include "brushinghandler.h" -#include "projectionobserver.h" static const int RNG_SEED = 1; @@ -158,7 +158,7 @@ int main(int argc, char **argv) TransitionControl *plotTC = engine.rootObjects()[0]->findChild("plotTC"); // Shared object which stores modifications to projections - ProjectionHistory history; + ProjectionHistory history(X, cpIndices); m->projectionHistory = &history; // Keep track of the current cp (in order to save them later, if requested) @@ -178,28 +178,20 @@ int main(int argc, char **argv) m->projectionHistory, &ProjectionHistory::addMap); // ... and update visual components whenever the history changes - QObject::connect(m->projectionHistory, &ProjectionHistory::mapAdded, - m, &Main::updateMap); - QObject::connect(m->projectionHistory, &ProjectionHistory::undoPerformed, - m, &Main::updateMap); - QObject::connect(m->projectionHistory, &ProjectionHistory::resetPerformed, + QObject::connect(m->projectionHistory, &ProjectionHistory::currentMapChanged, m, &Main::updateMap); // Keep both scatterplots and the splat scaled equally and relative to the // full plot MapScaleHandler mapScaleHandler; - QObject::connect(m->projectionHistory, &ProjectionHistory::mapAdded, - &mapScaleHandler, &MapScaleHandler::scaleToMap); - QObject::connect(m->projectionHistory, &ProjectionHistory::undoPerformed, - &mapScaleHandler, &MapScaleHandler::scaleToMap); - QObject::connect(m->projectionHistory, &ProjectionHistory::resetPerformed, - &mapScaleHandler, &MapScaleHandler::scaleToMap); QObject::connect(&mapScaleHandler, &MapScaleHandler::scaleChanged, m->cpPlot, &Scatterplot::setScale); QObject::connect(&mapScaleHandler, &MapScaleHandler::scaleChanged, m->rpPlot, &Scatterplot::setScale); QObject::connect(&mapScaleHandler, &MapScaleHandler::scaleChanged, m->splat, &VoronoiSplat::setScale); + QObject::connect(m->projectionHistory, &ProjectionHistory::currentMapChanged, + &mapScaleHandler, &MapScaleHandler::scaleToMap); QObject::connect(m->splat, &VoronoiSplat::colorScaleChanged, m->colormap, &Colormap::setColorScale); @@ -225,7 +217,7 @@ int main(int argc, char **argv) QObject::connect(&rpSelectionHandler, &SelectionHandler::selectionChanged, m->rpBarChart, &BarChart::setSelection); - // Brushing between bar chart and respective scatterplot + // Brushing between each bar chart and respective scatterplot BrushingHandler cpBrushHandler; QObject::connect(m->cpPlot, &Scatterplot::itemInteractivelyBrushed, &cpBrushHandler, &BrushingHandler::brushItem); @@ -246,37 +238,31 @@ int main(int argc, char **argv) QObject::connect(&rpBrushHandler, &BrushingHandler::itemBrushed, m->rpBarChart, &BarChart::brushItem); - // Recompute values whenever projection changes - ProjectionObserver projectionObserver(X, cpIndices); - m->projectionObserver = &projectionObserver; - QObject::connect(m->projectionHistory, &ProjectionHistory::mapAdded, - m->projectionObserver, &ProjectionObserver::addMap); - QObject::connect(m->projectionObserver, &ProjectionObserver::cpValuesChanged, + // Update visual components whenever values change + QObject::connect(m->projectionHistory, &ProjectionHistory::cpValuesChanged, m->cpPlot, &Scatterplot::setColorData); - QObject::connect(m->projectionObserver, &ProjectionObserver::rpValuesChanged, + QObject::connect(m->projectionHistory, &ProjectionHistory::rpValuesChanged, m->splat, &VoronoiSplat::setValues); - QObject::connect(m->projectionObserver, &ProjectionObserver::cpValuesChanged, + QObject::connect(m->projectionHistory, &ProjectionHistory::cpValuesChanged, m->cpBarChart, &BarChart::setValues); - QObject::connect(m->projectionObserver, &ProjectionObserver::rpValuesChanged, + QObject::connect(m->projectionHistory, &ProjectionHistory::rpValuesChanged, m->rpBarChart, &BarChart::setValues); // Recompute values whenever selection changes QObject::connect(&cpSelectionHandler, &SelectionHandler::selectionChanged, - &projectionObserver, &ProjectionObserver::setCPSelection); + m->projectionHistory, &ProjectionHistory::setCPSelection); QObject::connect(&rpSelectionHandler, &SelectionHandler::selectionChanged, - &projectionObserver, &ProjectionObserver::setRPSelection); + m->projectionHistory, &ProjectionHistory::setRPSelection); // Connect projection components to rewinding mechanism QObject::connect(plotTC, &TransitionControl::tChanged, - &manipulationHandler, &ManipulationHandler::setRewind); - QObject::connect(plotTC, &TransitionControl::tChanged, - m->projectionObserver, &ProjectionObserver::setRewind); + m->projectionHistory, &ProjectionHistory::setRewind); - QObject::connect(&manipulationHandler, &ManipulationHandler::mapRewound, + QObject::connect(m->projectionHistory, &ProjectionHistory::mapRewound, m, &Main::updateMap); - QObject::connect(m->projectionObserver, &ProjectionObserver::cpValuesRewound, + QObject::connect(m->projectionHistory, &ProjectionHistory::cpValuesRewound, m->cpPlot, &Scatterplot::setColorData); - QObject::connect(m->projectionObserver, &ProjectionObserver::rpValuesRewound, + QObject::connect(m->projectionHistory, &ProjectionHistory::rpValuesRewound, m->splat, &VoronoiSplat::setValues); // General component set up @@ -297,7 +283,6 @@ int main(int argc, char **argv) m->setCPBarChartColorScale(Main::ColorScaleRainbow); m->setRPBarChartColorScale(Main::ColorScaleRainbow); - // This sets the initial CP configuration, triggering all the necessary // signals to set up the helper objects and visual components manipulationHandler.setCP(Ys); diff --git a/main.h b/main.h index e1964e7..de3a7f4 100644 --- a/main.h +++ b/main.h @@ -6,7 +6,6 @@ #include "colorscale.h" #include "continuouscolorscale.h" -#include "projectionobserver.h" #include "projectionhistory.h" #include "numericrange.h" #include "barchart.h" @@ -76,25 +75,6 @@ public: cpPlot->setAcceptHoverEvents(true); } - enum ObserverType { - ObserverCurrent = ProjectionObserver::ObserverCurrent, - ObserverDiffPrevious = ProjectionObserver::ObserverDiffPrevious, - ObserverDiffFirst = ProjectionObserver::ObserverDiffFirst - }; - - Q_INVOKABLE bool setObserverType(ObserverType observerType) { - switch (observerType) { - case ObserverCurrent: - return projectionObserver->setType(ProjectionObserver::ObserverCurrent); - case ObserverDiffPrevious: - return projectionObserver->setType(ProjectionObserver::ObserverDiffPrevious); - case ObserverDiffFirst: - return projectionObserver->setType(ProjectionObserver::ObserverDiffFirst); - } - - return false; - } - enum ColorScaleType { ColorScaleCategorical, ColorScaleContinuous, @@ -139,17 +119,29 @@ public: Scatterplot *cpPlot, *rpPlot; VoronoiSplat *splat; - // Shared object that controls manipulation history + // Object that controls manipulation history ProjectionHistory *projectionHistory; - ProjectionObserver *projectionObserver; - Q_INVOKABLE void undoManipulation() { - projectionHistory->undo(); - projectionObserver->undo(); - } - Q_INVOKABLE void resetManipulation() { - projectionHistory->reset(); - projectionObserver->reset(); + Q_INVOKABLE void undoManipulation() { projectionHistory->undo(); } + Q_INVOKABLE void resetManipulation() { projectionHistory->reset(); } + + enum ObserverType { + ObserverCurrent = ProjectionHistory::ObserverCurrent, + ObserverDiffPrevious = ProjectionHistory::ObserverDiffPrevious, + ObserverDiffFirst = ProjectionHistory::ObserverDiffFirst + }; + + Q_INVOKABLE bool setObserverType(ObserverType observerType) { + switch (observerType) { + case ObserverCurrent: + return projectionHistory->setType(ProjectionHistory::ObserverCurrent); + case ObserverDiffPrevious: + return projectionHistory->setType(ProjectionHistory::ObserverDiffPrevious); + case ObserverDiffFirst: + return projectionHistory->setType(ProjectionHistory::ObserverDiffFirst); + } + + return false; } public slots: @@ -195,7 +187,6 @@ private: , cpPlot(0) , rpPlot(0) , splat(0) - , projectionObserver(0) , projectionHistory(0) { } diff --git a/manipulationhandler.cpp b/manipulationhandler.cpp index f561ad7..daaba01 100644 --- a/manipulationhandler.cpp +++ b/manipulationhandler.cpp @@ -35,13 +35,3 @@ void ManipulationHandler::setCP(const arma::mat &Ys) emit mapChanged(Y); } - -void ManipulationHandler::setRewind(double t) -{ - if (!m_history->hasPrev()) { - return; - } - - arma::mat Y = m_history->Y() * t + m_history->prev() * (1.0 - t); - emit mapRewound(Y); -} diff --git a/manipulationhandler.h b/manipulationhandler.h index b1aed61..9199c93 100644 --- a/manipulationhandler.h +++ b/manipulationhandler.h @@ -27,11 +27,9 @@ public: signals: void mapChanged(const arma::mat &Y) const; - void mapRewound(const arma::mat &Y) const; public slots: void setCP(const arma::mat &Ys); - void setRewind(double t); private: arma::mat m_X; diff --git a/pm.pro b/pm.pro index 5b91bc0..c6e0cb0 100644 --- a/pm.pro +++ b/pm.pro @@ -35,7 +35,6 @@ HEADERS += main.h \ numericrange.h \ selectionhandler.h \ brushinghandler.h \ - projectionobserver.h \ projectionhistory.h \ skelft.h \ skelftkernel.h \ @@ -56,7 +55,6 @@ SOURCES += main.cpp \ mapscalehandler.cpp \ selectionhandler.cpp \ brushinghandler.cpp \ - projectionobserver.cpp \ projectionhistory.cpp \ skelft_core.cpp \ lamp.cpp \ diff --git a/projectionhistory.cpp b/projectionhistory.cpp index bd55431..f450e0e 100644 --- a/projectionhistory.cpp +++ b/projectionhistory.cpp @@ -1,19 +1,66 @@ #include "projectionhistory.h" -ProjectionHistory::ProjectionHistory(QObject *parent) - : QObject(parent) +#include +#include + +#include "mp.h" +#include "numericrange.h" + +ProjectionHistory::ProjectionHistory(const arma::mat &X, + const arma::uvec &cpIndices) + : m_type(ObserverCurrent) + , m_X(X) + , m_cpIndices(cpIndices) + , m_rpIndices(X.n_rows - cpIndices.n_elem) + , m_cpSelectionEmpty(true) + , m_rpSelectionEmpty(true) + , m_values(X.n_rows) + , m_prevValues(X.n_rows) + , m_firstValues(X.n_rows) , m_hasFirst(false) , m_hasPrev(false) { + m_distX = mp::dist(m_X); + + NumericRange allIndices(0, m_X.n_rows); + std::set_symmetric_difference(allIndices.cbegin(), allIndices.cend(), + m_cpIndices.cbegin(), m_cpIndices.cend(), m_rpIndices.begin()); + + computeAlphas(); } +void ProjectionHistory::computeAlphas() +{ + m_influences.set_size(m_X.n_rows); + m_alphas.set_size(m_rpIndices.n_elem, m_cpIndices.n_elem); + + for (arma::uword i = 0; i < m_rpIndices.n_elem; i++) { + double sum = 0; + const arma::rowvec &x = m_X.row(m_rpIndices[i]); + for (arma::uword j = 0; j < m_cpIndices.n_elem; j++) { + double norm = arma::norm(x - m_X.row(m_cpIndices[j])); + m_alphas(i, j) = 1.0 / std::max(norm * norm, 1e-6); + sum += m_alphas(i, j); + } + + for (arma::uword j = 0; j < m_cpIndices.n_elem; j++) { + m_alphas(i, j) /= sum; + } + } +} void ProjectionHistory::undo() { if (m_hasPrev) { m_hasPrev = false; m_Y = m_prevY; + m_distY = m_prevDistY; + m_values = m_prevValues; - emit undoPerformed(m_Y); + emit undoPerformed(); + emit currentMapChanged(m_Y); + if (m_cpSelectionEmpty && m_rpSelectionEmpty) { + emitValuesChanged(); + } } } @@ -22,8 +69,14 @@ void ProjectionHistory::reset() if (m_hasFirst) { m_hasPrev = false; m_Y = m_firstY; + m_distY = m_firstDistY; + m_values = m_firstValues; - emit resetPerformed(m_Y); + emit resetPerformed(); + emit currentMapChanged(m_Y); + if (m_cpSelectionEmpty && m_rpSelectionEmpty) { + emitValuesChanged(); + } } } @@ -32,14 +85,142 @@ void ProjectionHistory::addMap(const arma::mat &Y) if (m_hasFirst) { m_hasPrev = true; m_prevY = m_Y; + m_prevDistY = m_distY; + m_prevValues = m_values; } m_Y = Y; + m_distY = mp::dist(Y); + + mp::aggregatedError(m_distX, m_distY, m_values); if (!m_hasFirst) { m_hasFirst = true; m_firstY = m_Y; + m_firstDistY = m_distY; + m_firstValues = m_values; + } + + emit currentMapChanged(m_Y); + if (m_cpSelectionEmpty && m_rpSelectionEmpty) { + emitValuesChanged(); + } +} + +bool ProjectionHistory::setType(ObserverType type) +{ + if (m_type == type) { + return true; + } + + if ((type == ObserverDiffPrevious && !m_hasPrev) + || (type == ObserverDiffFirst && !m_hasFirst)) { + return false; + } + + m_type = type; + if (!m_cpSelectionEmpty || !m_rpSelectionEmpty) { + // We changed our type, but cannot emit values since we have non-empty + // selections + return true; + } + return emitValuesChanged(); +} + +void ProjectionHistory::setCPSelection(const std::vector &cpSelection) +{ + m_cpSelection.clear(); + for (int i = 0; i < cpSelection.size(); i++) { + if (cpSelection[i]) { + m_cpSelection.push_back(i); + } + } + m_cpSelectionEmpty = m_cpSelection.empty(); + + if (!m_cpSelectionEmpty) { + // compute the influence of CP selection on each RP + for (arma::uword rp = 0; rp < m_rpIndices.n_elem; rp++) { + m_influences[m_rpIndices[rp]] = 0; + const arma::rowvec &row = m_alphas.row(rp); + for (auto cp: m_cpSelection) { + m_influences[m_rpIndices[rp]] += row[cp]; + } + } + + emit rpValuesChanged(m_influences(m_rpIndices)); + } else { + emitValuesChanged(); + } +} + +void ProjectionHistory::setRPSelection(const std::vector &rpSelection) +{ + m_rpSelection.clear(); + for (int i = 0; i < rpSelection.size(); i++) { + if (rpSelection[i]) { + m_rpSelection.push_back(i); + } + } + m_rpSelectionEmpty = m_rpSelection.empty(); + + if (!m_rpSelectionEmpty) { + // compute how influent is each CP on RP selection + for (arma::uword cp = 0; cp < m_cpIndices.n_elem; cp++) { + m_influences[m_cpIndices[cp]] = 0; + for (auto rp: m_rpSelection) { + m_influences[m_cpIndices[cp]] += m_alphas(rp, cp); + } + } + + emit cpValuesChanged(m_influences(m_cpIndices)); + } else { + emit cpValuesChanged(arma::vec()); + } +} + +bool ProjectionHistory::emitValuesChanged() const +{ + switch (m_type) { + case ObserverCurrent: + emit rpValuesChanged(m_values(m_rpIndices)); + emit valuesChanged(m_values); + return true; + case ObserverDiffPrevious: + if (m_hasPrev) { + arma::vec diff = m_values - m_prevValues; + emit rpValuesChanged(diff(m_rpIndices)); + emit valuesChanged(diff); + return true; + } + return false; + case ObserverDiffFirst: + if (m_hasFirst) { + arma::vec diff = m_values - m_firstValues; + emit rpValuesChanged(diff(m_rpIndices)); + emit valuesChanged(diff); + return true; + } + return false; + default: + return false; + } +} + +void ProjectionHistory::setRewind(double t) +{ + if (!m_hasPrev) { + return; + } + + arma::mat Y = m_Y * t + m_prevY * (1.0 - t); + emit mapRewound(Y); + + if (!m_cpSelectionEmpty || !m_rpSelectionEmpty) { + return; } - emit mapAdded(m_Y); + arma::vec values = m_values * t + m_prevValues * (1.0 - t); + emit cpValuesRewound(values(m_cpIndices)); + emit rpValuesRewound(values(m_rpIndices)); + emit valuesRewound(values); } diff --git a/projectionhistory.h b/projectionhistory.h index 9fe9ffc..a18af0c 100644 --- a/projectionhistory.h +++ b/projectionhistory.h @@ -10,11 +10,17 @@ class ProjectionHistory { Q_OBJECT public: - explicit ProjectionHistory(QObject *parent = 0); + enum ObserverType { + ObserverCurrent, + ObserverDiffPrevious, + ObserverDiffFirst + }; - const arma::mat &Y() const { return m_Y; } - const arma::mat &first() const { return m_firstY; } - const arma::mat &prev() const { return m_prevY; } + ProjectionHistory(const arma::mat &X, const arma::uvec &cpIndices); + + const arma::mat &Y() const { return m_Y; } + const arma::mat &firstY() const { return m_firstY; } + const arma::mat &prevY() const { return m_prevY; } bool hasFirst() const { return m_hasFirst; } bool hasPrev() const { return m_hasPrev; } @@ -23,15 +29,47 @@ public: void reset(); signals: - void undoPerformed(const arma::mat &prevY) const; - void resetPerformed(const arma::mat &firstY) const; - void mapAdded(const arma::mat &newY) const; + void undoPerformed() const; + void resetPerformed() const; + + void currentMapChanged(const arma::mat &Y) const; + void valuesChanged(const arma::vec &values) const; + void cpValuesChanged(const arma::vec &values) const; + void rpValuesChanged(const arma::vec &values) const; + + void mapRewound(const arma::mat &Y) const; + void valuesRewound(const arma::vec &values) const; + void cpValuesRewound(const arma::vec &values) const; + void rpValuesRewound(const arma::vec &values) const; public slots: void addMap(const arma::mat &Y); + bool setType(ObserverType type); + void setCPSelection(const std::vector &cpSelection); + void setRPSelection(const std::vector &rpSelection); + + void setRewind(double t); + private: - arma::mat m_Y, m_firstY, m_prevY; + bool emitValuesChanged() const; + + ObserverType m_type; + + arma::mat m_X, m_Y, m_firstY, m_prevY; + arma::mat m_distX, m_distY, m_firstDistY, m_prevDistY; + arma::uvec m_cpIndices, m_rpIndices; + + bool m_cpSelectionEmpty, m_rpSelectionEmpty; + std::vector m_cpSelection, m_rpSelection; + + // alpha(i, j): the influence CP j has on RP i + void computeAlphas(); + arma::mat m_alphas, m_influences; + + // TODO: one per implemented measure + arma::vec m_values, m_firstValues, m_prevValues; + bool m_hasFirst, m_hasPrev; }; diff --git a/projectionobserver.cpp b/projectionobserver.cpp deleted file mode 100644 index 94f266a..0000000 --- a/projectionobserver.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include "projectionobserver.h" - -#include -#include - -#include "mp.h" -#include "numericrange.h" - -ProjectionObserver::ProjectionObserver(const arma::mat &X, - const arma::uvec &cpIndices) - : m_type(ObserverCurrent) - , m_X(X) - , m_cpIndices(cpIndices) - , m_rpIndices(X.n_rows - cpIndices.n_elem) - , m_cpSelectionEmpty(true) - , m_rpSelectionEmpty(true) - , m_values(X.n_rows) - , m_prevValues(X.n_rows) - , m_firstValues(X.n_rows) - , m_hasFirst(false) - , m_hasPrev(false) -{ - m_distX = mp::dist(m_X); - - NumericRange allIndices(0, m_X.n_rows); - std::set_symmetric_difference(allIndices.cbegin(), allIndices.cend(), - m_cpIndices.cbegin(), m_cpIndices.cend(), m_rpIndices.begin()); - - computeAlphas(); -} - -void ProjectionObserver::computeAlphas() -{ - m_influences.set_size(m_X.n_rows); - m_alphas.set_size(m_rpIndices.n_elem, m_cpIndices.n_elem); - - for (arma::uword i = 0; i < m_rpIndices.n_elem; i++) { - double sum = 0; - const arma::rowvec &x = m_X.row(m_rpIndices[i]); - for (arma::uword j = 0; j < m_cpIndices.n_elem; j++) { - double norm = arma::norm(x - m_X.row(m_cpIndices[j])); - m_alphas(i, j) = 1.0 / std::max(norm * norm, 1e-6); - sum += m_alphas(i, j); - } - - for (arma::uword j = 0; j < m_cpIndices.n_elem; j++) { - m_alphas(i, j) /= sum; - } - } -} - -void ProjectionObserver::undo() -{ - if (m_hasPrev) { - m_hasPrev = false; - m_distY = m_prevDistY; - m_values = m_prevValues; - - if (m_cpSelectionEmpty && m_rpSelectionEmpty) { - emitValuesChanged(); - } - } -} - -void ProjectionObserver::reset() -{ - if (m_hasFirst) { - m_hasPrev = false; - m_distY = m_firstDistY; - m_values = m_firstValues; - - if (m_cpSelectionEmpty && m_rpSelectionEmpty) { - emitValuesChanged(); - } - } -} - -void ProjectionObserver::addMap(const arma::mat &Y) -{ - if (m_hasFirst) { - m_hasPrev = true; - m_prevDistY = m_distY; - m_prevValues = m_values; - } - - m_distY = mp::dist(Y); - - mp::aggregatedError(m_distX, m_distY, m_values); - - if (!m_hasFirst) { - m_hasFirst = true; - m_firstDistY = m_distY; - m_firstValues = m_values; - } - - if (m_cpSelectionEmpty && m_rpSelectionEmpty) { - emitValuesChanged(); - } -} - -bool ProjectionObserver::setType(ObserverType type) -{ - if (m_type == type) { - return true; - } - - if ((type == ObserverDiffPrevious && !m_hasPrev) - || (type == ObserverDiffFirst && !m_hasFirst)) { - return false; - } - - m_type = type; - if (!m_cpSelectionEmpty || !m_rpSelectionEmpty) { - // We changed our type, but cannot emit values since we have non-empty - // selections - return true; - } - return emitValuesChanged(); -} - -void ProjectionObserver::setCPSelection(const std::vector &cpSelection) -{ - m_cpSelection.clear(); - for (int i = 0; i < cpSelection.size(); i++) { - if (cpSelection[i]) { - m_cpSelection.push_back(i); - } - } - m_cpSelectionEmpty = m_cpSelection.empty(); - - if (!m_cpSelectionEmpty) { - // compute the influence of CP selection on each RP - for (arma::uword rp = 0; rp < m_rpIndices.n_elem; rp++) { - m_influences[m_rpIndices[rp]] = 0; - const arma::rowvec &row = m_alphas.row(rp); - for (auto cp: m_cpSelection) { - m_influences[m_rpIndices[rp]] += row[cp]; - } - } - - emit rpValuesChanged(m_influences(m_rpIndices)); - } else { - emitValuesChanged(); - } -} - -void ProjectionObserver::setRPSelection(const std::vector &rpSelection) -{ - m_rpSelection.clear(); - for (int i = 0; i < rpSelection.size(); i++) { - if (rpSelection[i]) { - m_rpSelection.push_back(i); - } - } - m_rpSelectionEmpty = m_rpSelection.empty(); - - if (!m_rpSelectionEmpty) { - // compute how influent is each CP on RP selection - for (arma::uword cp = 0; cp < m_cpIndices.n_elem; cp++) { - m_influences[m_cpIndices[cp]] = 0; - for (auto rp: m_rpSelection) { - m_influences[m_cpIndices[cp]] += m_alphas(rp, cp); - } - } - - emit cpValuesChanged(m_influences(m_cpIndices)); - } else { - emit cpValuesChanged(arma::vec()); - } -} - -bool ProjectionObserver::emitValuesChanged() const -{ - switch (m_type) { - case ObserverCurrent: - emit rpValuesChanged(m_values(m_rpIndices)); - emit valuesChanged(m_values); - return true; - case ObserverDiffPrevious: - if (m_hasPrev) { - arma::vec diff = m_values - m_prevValues; - emit rpValuesChanged(diff(m_rpIndices)); - emit valuesChanged(diff); - return true; - } - return false; - case ObserverDiffFirst: - if (m_hasFirst) { - arma::vec diff = m_values - m_firstValues; - emit rpValuesChanged(diff(m_rpIndices)); - emit valuesChanged(diff); - return true; - } - return false; - default: - return false; - } -} - -void ProjectionObserver::setRewind(double t) -{ - if (!m_hasPrev || !m_cpSelectionEmpty || !m_rpSelectionEmpty) { - return; - } - - arma::vec values = m_values * t + m_prevValues * (1.0 - t); - emit cpValuesRewound(values(m_cpIndices)); - emit rpValuesRewound(values(m_rpIndices)); - emit valuesRewound(values); -} diff --git a/projectionobserver.h b/projectionobserver.h deleted file mode 100644 index c021482..0000000 --- a/projectionobserver.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef PROJECTIONOBSERVER_H -#define PROJECTIONOBSERVER_H - -#include -#include - -#include "projectionhistory.h" - -class ProjectionObserver - : public QObject -{ - Q_OBJECT -public: - enum ObserverType { - ObserverCurrent, - ObserverDiffPrevious, - ObserverDiffFirst - }; - - ProjectionObserver(const arma::mat &X, - const arma::uvec &cpIndices); - - void undo(); - void reset(); - -signals: - void valuesChanged(const arma::vec &values) const; - void cpValuesChanged(const arma::vec &values) const; - void rpValuesChanged(const arma::vec &values) const; - void valuesRewound(const arma::vec &values) const; - void cpValuesRewound(const arma::vec &values) const; - void rpValuesRewound(const arma::vec &values) const; - -public slots: - void addMap(const arma::mat &Y); - bool setType(ObserverType type); - void setCPSelection(const std::vector &cpSelection); - void setRPSelection(const std::vector &rpSelection); - void setRewind(double t); - -private: - bool emitValuesChanged() const; - - ObserverType m_type; - arma::mat m_X; - arma::mat m_distX, m_distY, m_firstDistY, m_prevDistY; - arma::uvec m_cpIndices, m_rpIndices; - - bool m_cpSelectionEmpty, m_rpSelectionEmpty; - std::vector m_cpSelection, m_rpSelection; - - // alpha(i, j): the influence CP j has on RP i - void computeAlphas(); - arma::mat m_alphas, m_influences; - - // TODO: one per implemented measure - arma::vec m_values, m_firstValues, m_prevValues; - bool m_hasFirst, m_hasPrev; -}; - -#endif // PROJECTIONOBSERVER_H -- cgit v1.2.3