From a0bfd689d323334357dc54d4bda27123800ce831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Zbyszy=C5=84ski?= <github@mikezed.com> Date: Wed, 2 May 2018 11:45:10 +0100 Subject: [PATCH] this is in /tools now --- .../rapidVisualizer/BarChart.hpp | 72 +++++ .../rapidVisualizer/Graph.hpp | 122 +++++++++ .../rapidVisualizer/HistoryGraph.hpp | 125 +++++++++ .../rapidVisualizer/LineGraph.hpp | 85 ++++++ .../rapidVisualizer/LineGraphHistory.hpp | 87 ++++++ .../rapidVisualizer/RapidVisualization.cpp | 173 ++++++++++++ .../rapidVisualizer/RapidVisualization.hpp | 57 ++++ .../rapidVisualizer/RapidVisualizer.cpp | 259 ++++++++++++++++++ .../rapidVisualizer/RapidVisualizer.hpp | 79 ++++++ .../rapidVisualizer/RealTimeGraph.hpp | 107 ++++++++ .../rapidVisualizer/ScopeWithHistory.hpp | 184 +++++++++++++ 11 files changed, 1350 insertions(+) create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/BarChart.hpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/Graph.hpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/HistoryGraph.hpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraph.hpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraphHistory.hpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.cpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.hpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.cpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.hpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/RealTimeGraph.hpp create mode 100644 examples/ofx/Bitalino_rapidmix/rapidVisualizer/ScopeWithHistory.hpp diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/BarChart.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/BarChart.hpp new file mode 100644 index 0000000..379b2df --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/BarChart.hpp @@ -0,0 +1,72 @@ +// +// BarChart.hpp +// RapidVisualizerOSC +// +// Created by James on 09/11/2017. +// +// + +#ifndef BarChart_hpp +#define BarChart_hpp + +#include <stdio.h> +#include "RealTimeGraph.hpp" + +class BarChart : public RealTimeGraph +{ +public: + BarChart ( GraphState* state ) : RealTimeGraph (state) + { + // + } + ~BarChart ( void ) + { + // + } + void updateRep ( void ) + { + // + } + void drawSubGraph ( std::string subLabel, DataContainer<std::vector<double>>& data, ofRectangle subLabelRect ) + { + double + minIn = 0, + minOut = 0, + maxOut = -subLabelRect.height, + startPosY = subLabelRect.height, + barSize = subLabelRect.width/data.labelData.size(), + separation = barSize/16, + halfSeparation = separation/2; + bool drawZeroSep = false; + + if (data.minValue < 0) + { // Add negative part + startPosY = subLabelRect.height/2; + minIn = -data.maxValue; + minOut = subLabelRect.height/2; + maxOut /= 2; + drawZeroSep = true; + } + for (uint32_t i = 0; i < data.labelData.size(); ++i) + { + double output = mapVals(data.labelData[i], minIn, data.maxValue, minOut, maxOut ); + ofSetColor (graphColor); + ofFill(); + ofDrawRectangle(subLabelRect.x + barSize * i + halfSeparation, subLabelRect.y + startPosY, barSize - separation, output ); + + } + if (drawZeroSep) + { + ofSetLineWidth(1.25); + ofSetColor (175,150,150); + ofDrawLine(subLabelRect.x, subLabelRect.y + startPosY, + subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY); + } + } + void update ( void ) + { + // + } +}; + +#endif /* BarChart_hpp */ diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/Graph.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/Graph.hpp new file mode 100644 index 0000000..546785f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/Graph.hpp @@ -0,0 +1,122 @@ +// +// Graph.hpp +// RapidVisualizerOSC +// +// Created by James on 09/11/2017. +// +// + +#ifndef Graph_h +#define Graph_h + +#include <string> +#include <vector> +#include <list> +#include "ofMain.h" +#include "ofxGui.h" + +// TODO: add namespace, move funcs and struct to other header(s) +enum class TextAlignment { + LEFT, + CENTER, + RIGHT +}; + +static inline void drawTextLabel ( std::string label, ofVec2f position, ofColor labelBackgroundColor, ofColor stringColor, TextAlignment alignment, bool drawAbove ) +{ + uint32_t strLenPix = label.length()*8; + + switch (alignment) { + case TextAlignment::LEFT: + // No exception + break; + case TextAlignment::CENTER: + position.x -= strLenPix / 2; + break; + case TextAlignment::RIGHT: + position.x -= strLenPix; + break; + default: + break; + } + + ofSetColor (labelBackgroundColor); + ofRectangle bmpStringRect(position.x - 2, + position.y + ((drawAbove) ? -4 : 12) + 2, + strLenPix + 4, -12); + ofDrawRectangle(bmpStringRect); + + ofSetColor (stringColor); + ofDrawBitmapString(label, position.x, position.y + ((drawAbove) ? -4 : 12)); +} + +static inline double mapVals ( double x, double in_min, double in_max, double out_min, double out_max ) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +template <typename T> +struct DataContainer { + T labelData; + double minValue = 0.0; + double maxValue = 1.0; + uint32_t iteratorPos = 0; + //ofColor graphColor; + + void updateMinMax ( void ) + { + auto mm = std::minmax_element(labelData.begin(), labelData.end()); + double min = labelData[std::distance(labelData.begin(), mm.first)]; + double max = labelData[std::distance(labelData.begin(), mm.second)]; + + if (min < minValue) + minValue = min; + if (max > maxValue) + maxValue = max; + if (fabs(min) > maxValue) + maxValue = fabs(min); + + } +}; + +class Graph { +public: + enum graphLayout { + GRAPHS_STACKED, + GRAPHS_VERTICAL + }; + struct GraphState { + std::string label; + graphLayout layout = graphLayout::GRAPHS_STACKED; + bool hasHistory = false; + ofRectangle positionAndSize; + uint32_t historySize; + }; + + Graph ( GraphState* state ) + : state(state) + { + graphColor = ofColor(24, 219, 92); + textColor = ofColor(255, 157, 117); + } + + virtual ~Graph ( void ) + { + + } + + virtual void updateRep ( void ) = 0; // update representation + virtual void addData ( std::string subLabel, std::vector<double>& data ) = 0; + virtual void reset ( void ) = 0; + + virtual void update ( void ) = 0; + virtual void draw ( void ) = 0; + + virtual uint32_t getNumSubGraphs ( void ) const = 0; +protected: + GraphState *state = nullptr; + ofColor graphColor; + ofColor textColor; +}; + +#endif /* Graph_h */ diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/HistoryGraph.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/HistoryGraph.hpp new file mode 100644 index 0000000..8086167 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/HistoryGraph.hpp @@ -0,0 +1,125 @@ +// +// HistoryGraph.hpp +// RapidVisualizerOSC +// +// Created by James on 09/11/2017. +// +// + +#ifndef HistoryGraph_h +#define HistoryGraph_h + +#include "Graph.hpp" +#include <list> + +class HistoryGraph : public Graph +{ +public: + HistoryGraph ( GraphState* state ) + : Graph(state) + { + + } + ~HistoryGraph ( void ) + { + } + + virtual void updateRep ( void ) = 0; // update representation + virtual void drawSubGraph ( std::string subLabel, DataContainer<std::list<double>>& data, ofRectangle subLabelrect ) = 0; + virtual void update ( void ) = 0; + + void addData ( std::string subLabel, std::vector<double>& data ) + { + if (data.size() < state->historySize) + { + //FIXME: can be sped up by using the result of this search instead of accessing by[] again + if ( subLabelData.find(subLabel) == subLabelData.end() ) { + // not found + DataContainer<std::list<double>> container; + container.labelData.resize(state->historySize); + std::fill(container.labelData.begin(), container.labelData.end(), 0.0); + subLabelData[subLabel] = container; + + } + DataContainer<std::list<double>>& dataRef = subLabelData[subLabel]; + list<double>& referencedList = dataRef.labelData; + while (referencedList.size() + data.size() >= state->historySize) + { + referencedList.pop_front(); + } + for (int32_t i = data.size()-1; i >= 0; --i) + { + double val = data[i]; + if (val < dataRef.minValue) + dataRef.minValue = val; + if (val > dataRef.maxValue) + dataRef.maxValue = val; + if (fabs(val) > dataRef.maxValue) + dataRef.maxValue = fabs(val); + referencedList.push_back(val); + } + } + } + + void reset ( void ) + { + subLabelData.clear(); + } + + void draw ( void ) + { + uint32_t numElements = subLabelData.size(); + uint16_t heightBetweenSubLabels = state->positionAndSize.height/numElements; + uint16_t subLabelY = 0; + + ofSetColor (textColor); + ofDrawLine(state->positionAndSize.x, state->positionAndSize.y + heightBetweenSubLabels - 1.5, + state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y + heightBetweenSubLabels - 1.5); + + std::map<std::string, DataContainer<std::list<double>>>::iterator it; + for(it = subLabelData.begin(); it != subLabelData.end(); ++it) + { + std::string subLabel = it->first; + DataContainer<std::list<double>>& data = it->second; + + drawSubGraph (subLabel, data, ofRectangle(state->positionAndSize.x, + state->positionAndSize.y + subLabelY + 3, + state->positionAndSize.width, + heightBetweenSubLabels - 6)); + // Draw label and background + drawTextLabel(subLabel, ofVec2f(state->positionAndSize.x + state->positionAndSize.width, + state->positionAndSize.y + subLabelY), + ofColor(100, 100, 100), ofColor(textColor), TextAlignment::RIGHT, false); + + + // Draw max value + drawTextLabel(ofToString(data.maxValue), + ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2, + state->positionAndSize.y + subLabelY), + ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, false); + + // Increment Y position + subLabelY += heightBetweenSubLabels; + + // Draw min value + // Show actual min value? + drawTextLabel(ofToString((data.minValue < 0) ? -data.maxValue : 0), + ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2, + state->positionAndSize.y + subLabelY), + ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, true); + + // Draw Line at bottom of graph + //ofSetLineWidth(2.0); + //ofSetColor (180,180,180); + /*ofDrawLine(state->positionAndSize.x, state->positionAndSize.y + subLabelY + 3, + state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y + subLabelY + 3);*/ + } + } + uint32_t getNumSubGraphs ( void ) const + { + return subLabelData.size(); + } +protected: + std::map <std::string, DataContainer<std::list<double>>> subLabelData; +}; +#endif /* HistoryGraph_h */ diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraph.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraph.hpp new file mode 100644 index 0000000..88669d9 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraph.hpp @@ -0,0 +1,85 @@ +// +// LineGraph.hpp +// RapidVisualizerOSC +// +// Created by James on 09/11/2017. +// +// + +#ifndef LineGraph_h +#define LineGraph_h + +#include <stdio.h> +#include "RealTimeGraph.hpp" + +class LineGraph : public RealTimeGraph +{ +public: + LineGraph ( GraphState* state ) : RealTimeGraph (state) + { + // + } + ~LineGraph ( void ) + { + // + } + void updateRep ( void ) + { + // + } + void drawSubGraph ( std::string subLabel, DataContainer<std::vector<double>>& data, ofRectangle subLabelRect ) + { + double + minIn = 0, + minOut = 0, + maxOut = -subLabelRect.height, + startPosY = subLabelRect.height, + pointDistance = subLabelRect.width/data.labelData.size(), + separation = pointDistance/2; + //halfSeparation = separation/2; + bool drawZeroSep = false; + + if (data.minValue < 0) + { // Add negative part + startPosY = subLabelRect.height/2; + minIn = -data.maxValue; + minOut = subLabelRect.height/2; + maxOut /= 2; + drawZeroSep = true; + } + + ofBeginShape(); + ofFill(); + ofVertex(subLabelRect.x, subLabelRect.y + startPosY); + double output = mapVals(data.labelData[0], minIn, data.maxValue, minOut, maxOut ); + ofVertex(subLabelRect.x, subLabelRect.y + startPosY + output); + for (uint32_t i = 0; i < data.labelData.size(); ++i) + { + output = mapVals(data.labelData[i], minIn, data.maxValue, minOut, maxOut ); + ofSetColor (graphColor); + + ofVertex(subLabelRect.x + pointDistance * i + separation, subLabelRect.y + startPosY + output); + //ofDrawRectangle(subLabelRect.x + barSize * i + halfSeparation, subLabelRect.y + startPosY, barSize - separation, output ); + + } + output = mapVals(data.labelData[data.labelData.size()-1], minIn, data.maxValue, minOut, maxOut ); + ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY + output); + ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY); + ofEndShape(); + + if (drawZeroSep) + { + ofSetLineWidth(1.25); + ofSetColor (175,150,150); + ofDrawLine(subLabelRect.x, subLabelRect.y + startPosY, + subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY); + } + } + void update ( void ) + { + // + } +}; + + +#endif /* LineGraph_h */ diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraphHistory.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraphHistory.hpp new file mode 100644 index 0000000..e3b32f8 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/LineGraphHistory.hpp @@ -0,0 +1,87 @@ +// +// LineGraphHistory.hpp +// RapidVisualizerOSC +// +// Created by James on 10/11/2017. +// +// + +#ifndef LineGraphHistory_h +#define LineGraphHistory_h + +#include <stdio.h> +#include "HistoryGraph.hpp" + +class LineGraphHistory : public HistoryGraph +{ +public: + LineGraphHistory ( GraphState* state ) : HistoryGraph (state) + { + // + } + ~LineGraphHistory ( void ) + { + // + } + void updateRep ( void ) + { + // + } + void drawSubGraph ( std::string subLabel, DataContainer<std::list<double>>& data, ofRectangle subLabelRect ) + { + double + minIn = 0, + minOut = 0, + maxOut = -subLabelRect.height, + startPosY = subLabelRect.height, + pointDistance = subLabelRect.width/data.labelData.size(), + separation = pointDistance/2; + //halfSeparation = separation/2; + bool drawZeroSep = false; + + if (data.minValue < 0) + { // Add negative part + startPosY = subLabelRect.height/2; + minIn = -data.maxValue; + minOut = subLabelRect.height/2; + maxOut /= 2; + drawZeroSep = true; + } + + ofBeginShape(); + ofFill(); + ofVertex(subLabelRect.x, subLabelRect.y + startPosY); + double output = mapVals(data.labelData.front(), minIn, data.maxValue, minOut, maxOut ); + ofVertex(subLabelRect.x, subLabelRect.y + startPosY + output); + uint32_t i = 0; + for (double d : data.labelData) + { + output = mapVals(d, minIn, data.maxValue, minOut, maxOut ); + ofSetColor (graphColor); + + ofVertex(subLabelRect.x + pointDistance * i + separation, subLabelRect.y + startPosY + output); + //ofDrawRectangle(subLabelRect.x + barSize * i + halfSeparation, subLabelRect.y + startPosY, barSize - separation, output ); + ++i; + + } + output = mapVals(data.labelData.back(), minIn, data.maxValue, minOut, maxOut ); + ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY + output); + ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY); + ofEndShape(); + + if (drawZeroSep) + { + ofSetLineWidth(1.25); + ofSetColor (175,150,150); + ofDrawLine(subLabelRect.x, subLabelRect.y + startPosY, + subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY); + } + } + void update ( void ) + { + // + } +}; + + +#endif /* LineGraphHistory_h */ diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.cpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.cpp new file mode 100644 index 0000000..dc2bc83 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.cpp @@ -0,0 +1,173 @@ +// +// RapidVisualization.cpp +// RapidVisualizerOSC +// +// Created by James on 13/11/2017. +// +// + +#include <stdio.h> +#include "RapidVisualization.hpp" + +RapidVisualization::RapidVisualization ( void ) +{ + +} + +RapidVisualization::~RapidVisualization ( void ) +{ + std::map<std::string, RapidVisualizer*>::iterator it; + for(it = visualizers.begin(); it != visualizers.end(); ++it) + { + if (it->second) + delete it->second; + } +} + +void RapidVisualization::setup ( ofRectangle posAndSize, uint32_t defaultHistorySize ) +{ + this->posAndSize = posAndSize; + this->defaultHistorySize = defaultHistorySize; +} + +std::pair<std::string, std::string> RapidVisualization::getRoute(std::string& address) +{ + std::pair<std::string, std::string> ret; + size_t delimPos = address.substr(1).find("/"); + if (delimPos != std::string::npos) + { + delimPos += 1; + ret.first = address.substr(0, delimPos); + ret.second = address.substr(delimPos); + } + else + { + ret.first = address.substr(0, address.length()); + ret.second = "/"; + } + return ret; +} + +void RapidVisualization::addData ( std::string address, std::vector<double>& data ) +{ + std::pair<std::string, std::string> route = getRoute(address); + if ( visualizers.find(route.first) == visualizers.end() ) { + RapidVisualizer* ptr = visualizers[route.first] = new RapidVisualizer(); // Add new graph + ptr->setup(route.first, RapidVisualizer::LINE_GRAPH_WITH_HISTORY, defaultHistorySize, Graph::GRAPHS_STACKED, false, ofRectangle(0,0,100,100)); + } + + RapidVisualizer* rapidVizPtr = visualizers[route.first]; + rapidVizPtr->addData(address, data); + updateRep(); +} + +void RapidVisualization::addData ( std::string graphName, std::string subGraphName, std::vector<double>& data ) +{ + if ( visualizers.find(graphName) == visualizers.end() ) { + RapidVisualizer* ptr = visualizers[graphName] = new RapidVisualizer(); // Add new graph + ptr->setup(graphName, RapidVisualizer::LINE_GRAPH_WITH_HISTORY, defaultHistorySize, Graph::GRAPHS_STACKED, false, ofRectangle(0,0,100,100)); + } + + RapidVisualizer* rapidVizPtr = visualizers[graphName]; + rapidVizPtr->addData(subGraphName, data); + updateRep(); +} + +void RapidVisualization::reset ( void ) +{ + std::map<std::string, RapidVisualizer*>::iterator it; + for(it = visualizers.begin(); it != visualizers.end(); ++it) + { + if (it->second) + delete it->second; + } + visualizers.clear(); +} + +void RapidVisualization::update ( void ) +{ + uint32_t tempNumGraphs = 0; + bool resetCase = false; // This is terrible (stops jitter when selecting new graph type) + std::map<std::string, RapidVisualizer*>::iterator it; + for(it = visualizers.begin(); it != visualizers.end(); ++it) + { + it->second->update(); + uint32_t tGraph = it->second->getNumGraphs(); + if (tGraph == 0) + { + resetCase = true; + break; + } + tempNumGraphs += tGraph; + } + if (tempNumGraphs != numGraphs && !resetCase) + { + numGraphs = tempNumGraphs; + updateRep(); + } +} + +void RapidVisualization::draw ( void ) +{ + std::map<std::string, RapidVisualizer*>::iterator it; + for(it = visualizers.begin(); it != visualizers.end(); ++it) + { + it->second->draw(); + } + if (!guiHidden) + for(it = visualizers.begin(); it != visualizers.end(); ++it) + { + it->second->drawMenu(posAndSize); // Stop menu being behind next graph + } + if (numGraphs == 0) + { + drawTextLabel("Waiting for data", ofVec2f(posAndSize.x+posAndSize.width/2, posAndSize.y), ofColor(24, 219, 92), ofColor(255, 157, 117), TextAlignment::CENTER, false ); + } +} + +void RapidVisualization::setPos ( ofVec2f pos ) +{ + posAndSize.x = pos.x; + posAndSize.y = pos.y; + updateRep(); +} +void RapidVisualization::setSize ( ofVec2f size ) +{ + posAndSize.width = size.x; + posAndSize.height = size.y; + updateRep(); +} + +void RapidVisualization::setPosAndSize ( ofRectangle posAndSize ) +{ + this->posAndSize = posAndSize; + updateRep(); +} + +void RapidVisualization::setHistorySize ( uint32_t size ) +{ + defaultHistorySize = size; +} + +void RapidVisualization::updateRep ( void ) +{ + double graphHeight = posAndSize.height/numGraphs; // Height of single graph + std::map<std::string, RapidVisualizer*>::iterator it; + double drawHeight = posAndSize.y; + double height; + for(it = visualizers.begin(); it != visualizers.end(); ++it) + { + height = it->second->getNumGraphs()*graphHeight; + it->second->setRect(ofRectangle(posAndSize.x, + drawHeight, + posAndSize.width, + height)); + + drawHeight += height; + } +} + +void RapidVisualization::setGuiHidden ( bool guiHidden ) +{ + this->guiHidden = guiHidden; +} diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.hpp new file mode 100644 index 0000000..5485e6c --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualization.hpp @@ -0,0 +1,57 @@ +// +// RapidVisualization.hpp +// RapidVisualizerOSC +// +// Created by James on 10/11/2017. +// +// + +#ifndef RapidVisualization_h +#define RapidVisualization_h + +#include "RapidVisualizer.hpp" + +class RapidVisualization +{ +public: + RapidVisualization ( void ); + ~RapidVisualization ( void ); + + void setup ( ofRectangle posAndSize, uint32_t defaultHistorySize=256 ); + + // Append multiple types of graphs to cycle through as new entry addresses are added + // Implement? + //RapidVisualizer* addGraphType ( RapidVisualizer::graphTypeRealtime graphType ); + //RapidVisualizer* addGraphType ( RapidVisualizer::graphTypeWithHistory graphType, uint32_t historySize ); + + void addData ( std::string address, std::vector<double>& data ); + void addData ( std::string graphName, std::string subGraphName, std::vector<double>& data ); + void reset ( void ); + + void update ( void ); + void draw ( void ); + + void setPos ( ofVec2f pos ); + void setSize ( ofVec2f size ); + void setPosAndSize ( ofRectangle posAndSize ); + + void setHistorySize ( uint32_t size ); + void setGraphColor ( ofColor graphColor ); + //void setGraphColor ( ofColor backgroundColor ); + //void setGraphColor ( ofColor textColor ); + + void setGuiHidden ( bool guiHidden ); + +private: + bool guiHidden = false; + uint32_t numGraphs = 0; + std::map<std::string, RapidVisualizer*> visualizers; + ofRectangle posAndSize; + + uint32_t defaultHistorySize; + + std::pair<std::string, std::string> getRoute ( std::string& address ); + void updateRep ( void ); +}; + +#endif /* RapidVisualization_h */ diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.cpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.cpp new file mode 100644 index 0000000..1fe723f --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.cpp @@ -0,0 +1,259 @@ +// +// RapidVisualizer.cpp +// RapidVisualizerOSC +// +// Created by James on 09/11/2017. +// +// + +#include "RapidVisualizer.hpp" + +RapidVisualizer::RapidVisualizer ( void ) +{ + uint32 initialHistorySize = 256; + minimumGui.setup(); + expandedGui.setBackgroundColor(ofColor(0,0,0,127)); + expandedGui.setup(); + + historySizeSlider.addListener(this, &RapidVisualizer::historySizeSliderChanged); + + auto gNameRef = expandButton.setup(graphState.label, false); + expandButton.setBackgroundColor(ofColor(0, 0, 0, 127)); + minimumGui.add(gNameRef); + + expandedGui.add(graphTypesLabel.setup("Graph Type","")); + expandedGui.add(viewTypes[0].setup("Bar Chart", false)); + expandedGui.add(viewTypes[1].setup("Line Graph", false)); + expandedGui.add(viewTypes[2].setup("Line Graph History", false)); + expandedGui.add(viewTypes[3].setup("Scope", false)); + expandedGui.add(prefLabel.setup("Preferences","")); + expandedGui.add(splitArrayIntoGraphs.setup("Split Multiple Input", false)); + expandedGui.add(historySizeSlider.setup("History Size", initialHistorySize, 4, 4096)); + + setHistory(initialHistorySize); + setLayout (Graph::GRAPHS_STACKED); + setSplitEachArgument (false); + setRect (ofRectangle(0,0,200,200)); +} + +RapidVisualizer::~RapidVisualizer ( void ) +{ + if (currentGraph) + { + delete currentGraph; + } +} + +void RapidVisualizer::setup ( std::string label, graphTypeT graphType, Graph::graphLayout layout, bool splitEachArgument, ofRectangle positionAndSize ) +{ + + setLabel (label); + setLayout (layout); + setSplitEachArgument (splitEachArgument); + setRect (positionAndSize); + setGraphType (graphType); // FIXME: Check if successfully initialized +} + +void RapidVisualizer::setup ( std::string label, graphTypeT graphType, uint32_t historySize, Graph::graphLayout layout, bool splitEachArgument, ofRectangle positionAndSize ) +{ + setLabel (label); + setLayout (layout); + setSplitEachArgument (splitEachArgument); + setRect (positionAndSize); + setGraphType (graphType, historySize); // FIXME: Check if successfully initialized +} + +void RapidVisualizer::setLabel ( std::string label ) +{ + graphState.label = label; + expandButton.setName(label); + if (currentGraph) + currentGraph->updateRep(); +} + +void RapidVisualizer::setGraphType ( graphTypeT graphType ) +{ + if (currentGraphType != graphType) + { + if (currentGraph) + { + // TODO: add lock for when doing this, or have all types loaded? + delete currentGraph; + } + switch (graphType) { + case BAR_CHART: + currentGraph = new BarChart ( &graphState ); + graphState.hasHistory = false; + break; + case LINE_GRAPH: + currentGraph = new LineGraph ( &graphState ); + graphState.hasHistory = false; + break; + case LINE_GRAPH_WITH_HISTORY: + currentGraph = new LineGraphHistory ( &graphState ); + graphState.hasHistory = true; + break; + case SCOPE: + currentGraph = new ScopeWithHistory ( &graphState ); + graphState.hasHistory = true; + break; + default: + break; + } + currentGraphType = graphType; + } +} + +void RapidVisualizer::setGraphType ( graphTypeT graphType, uint32_t historySize ) +{ + setHistory(historySize); + setGraphType(graphType); +} + +void RapidVisualizer::setLayout ( Graph::graphLayout layout ) +{ + graphState.layout = layout; + if (currentGraph) + currentGraph->updateRep(); +} + +void RapidVisualizer::setSplitEachArgument ( bool splitEachArgument ) +{ + this->splitEachArgument = splitEachArgument; + splitArrayIntoGraphs = splitEachArgument; +} + +void RapidVisualizer::setPos ( ofVec2f pos ) +{ + graphState.positionAndSize.x = pos.x; + graphState.positionAndSize.y = pos.y; + if (currentGraph) + currentGraph->updateRep(); +} + +void RapidVisualizer::setSize ( ofVec2f size ) +{ + graphState.positionAndSize.width = size.x; + graphState.positionAndSize.height = size.y; + if (currentGraph) + currentGraph->updateRep(); +} + +void RapidVisualizer::setRect ( ofRectangle positionAndSize ) +{ + graphState.positionAndSize = positionAndSize; + if (currentGraph) + currentGraph->updateRep(); +} + +void RapidVisualizer::setHistory( uint32_t historySize ) +{ + graphState.historySize = historySize; + historySizeSlider = historySize; + if (currentGraph) + currentGraph->updateRep(); +} + +void RapidVisualizer::historySizeSliderChanged (int32_t &val) +{ + setHistory(val); +} + +void RapidVisualizer::addData ( std::string subLabel, std::vector<double>& data ) +{ + if (currentGraph) + { + if (splitEachArgument && data.size() > 1) + { + int16_t currentIndex = 0; + std::vector<double> splitData; + for (double d : data) + { + splitData = {d}; + currentGraph->addData (subLabel + ofToString(currentIndex), splitData); + ++currentIndex; + } + } + else + currentGraph->addData (subLabel, data); + } +} + +void RapidVisualizer::update ( void ) +{ + if (currentGraph) + { + currentGraph->update(); + } +} + +void RapidVisualizer::drawMenu ( ofRectangle mainPosAndSize ) +{ + minimumGui.setPosition(graphState.positionAndSize.x, graphState.positionAndSize.y); + minimumGui.draw(); + if (menuActive) + { + double expandedGuiXPos = graphState.positionAndSize.x + minimumGui.getWidth(); + double expandedGuiYPos = graphState.positionAndSize.y; + double mainYPlusHeight = mainPosAndSize.y + mainPosAndSize.height; + double check = expandedGuiYPos + expandedGui.getHeight() - mainYPlusHeight; + + if (check > 0) + { + expandedGuiYPos -= check; + } + + expandedGui.setPosition(expandedGuiXPos, expandedGuiYPos); + expandedGui.draw(); + } +} + +void RapidVisualizer::draw ( void ) +{ + + if (currentGraph) + { + currentGraph->draw(); + } + //drawMenu(); + menuActive = expandButton; + if (menuActive) + { + bool noneActive = true; + for (uint8_t i = 0; i < NUMVIEWTYPES; ++i) + { + if (viewTypes[i] && !oldTypeToggles[i]) + { + std::fill(viewTypes, viewTypes + NUMVIEWTYPES, false); + viewTypes[i] = true; + setGraphType(static_cast<graphTypeT>(i)); + } + if (viewTypes[i]) + noneActive = false; + oldTypeToggles[i] = viewTypes[i]; + } + if (noneActive && currentGraphType != NOT_INITIALIZED) + { + viewTypes[currentGraphType] = true; + } + if (splitEachArgument != splitArrayIntoGraphs) + { + // Dirty, solution for now + if (currentGraph) + currentGraph->reset(); + splitEachArgument = splitArrayIntoGraphs; + } + } +} + +uint32_t RapidVisualizer::getNumGraphs ( void ) const +{ + if (currentGraph) + { + return currentGraph->getNumSubGraphs(); + } else { + return 0; + } +} + +#undef NUMVIEWTYPES diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.hpp new file mode 100644 index 0000000..0e4a9f2 --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RapidVisualizer.hpp @@ -0,0 +1,79 @@ +// +// RapidVisualizer.hpp +// RapidVisualizerOSC +// +// Created by James on 09/11/2017. +// +// + +#ifndef RapidVisualizer_hpp +#define RapidVisualizer_hpp + +#include <stdio.h> +#include <map> +#include "ofMain.h" +#include "Graph.hpp" +#include "BarChart.hpp" +#include "LineGraph.hpp" +#include "LineGraphHistory.hpp" +#include "ScopeWithHistory.hpp" + +#define NUMVIEWTYPES 4 + +// TODO add historySize slider and init with default 256 or so + +class RapidVisualizer { +public: + enum graphTypeT { + BAR_CHART, + LINE_GRAPH, + LINE_GRAPH_WITH_HISTORY, + SCOPE, + NOT_INITIALIZED + }; + + RapidVisualizer ( void ); + ~RapidVisualizer ( void ); + + void setup ( std::string label, graphTypeT graphType, Graph::graphLayout layout, bool splitEachArgument, ofRectangle positionAndSize ); + void setup ( std::string label, graphTypeT graphType, uint32_t historySize, Graph::graphLayout layout, bool splitEachArgument, ofRectangle positionAndSize ); + + void setLabel ( std::string label ); + void setGraphType ( graphTypeT graphType ); + void setGraphType ( graphTypeT graphType, uint32_t historySize ); + void setLayout ( Graph::graphLayout layout ); + void setSplitEachArgument ( bool splitEachArgument ); + void setPos ( ofVec2f pos ); + void setSize ( ofVec2f size ); + void setRect ( ofRectangle rect ); + void setHistory ( uint32_t historySize ); + void historySizeSliderChanged (int32_t &val); + + void addData ( std::string subLabel, std::vector<double>& data ); + void update ( void ); + void drawMenu ( ofRectangle mainPosAndSize ); + void draw ( void ); + + uint32_t getNumGraphs ( void ) const; + +private: + graphTypeT currentGraphType = NOT_INITIALIZED; + Graph::GraphState graphState; + Graph* currentGraph = nullptr; + bool splitEachArgument = false; + bool menuActive = false; + + ofxLabel graphName; + ofxLabel graphTypesLabel; + ofxLabel prefLabel; + ofxPanel minimumGui; + ofxToggle expandButton; + ofxPanel expandedGui; + ofxIntSlider historySizeSlider; + ofxToggle splitArrayIntoGraphs; + + bool oldTypeToggles[NUMVIEWTYPES]; + ofxToggle viewTypes[NUMVIEWTYPES]; +}; + +#endif /* RapidVisualizer_hpp */ diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RealTimeGraph.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RealTimeGraph.hpp new file mode 100644 index 0000000..99e928e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/RealTimeGraph.hpp @@ -0,0 +1,107 @@ +// +// RealTimeGraph.hpp +// RapidVisualizerOSC +// +// Created by James on 09/11/2017. +// +// + +#ifndef RealTimeGraph_h +#define RealTimeGraph_h + +#include <map> +#include <vector> +#include <string> +#include "Graph.hpp" + +class RealTimeGraph : public Graph +{ +public: + RealTimeGraph ( GraphState* state ) + : Graph(state) + { + } + ~RealTimeGraph ( void ) + { + } + + void addData ( std::string subLabel, std::vector<double>& data ) + { + if ( subLabelData.find(subLabel) == subLabelData.end() ) { + // not found + subLabelData[subLabel] = DataContainer<std::vector<double>>(); + } + + subLabelData[subLabel].labelData = data; + subLabelData[subLabel].updateMinMax(); + } + + virtual void reset ( void ) + { + subLabelData.clear(); + } + + virtual void updateRep ( void ) = 0; // update representation + virtual void drawSubGraph ( std::string subLabel, DataContainer<std::vector<double>>& data, ofRectangle subLabelrect ) = 0; + + virtual void update ( void ) = 0; + + void draw ( void ) + { + uint32_t numElements = subLabelData.size(); + uint16_t heightBetweenSubLabels = state->positionAndSize.height/numElements; + uint16_t subLabelY = 0; + + ofSetColor (255,255,255); + ofDrawLine(state->positionAndSize.x, state->positionAndSize.y, + state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y); + + std::map<std::string, DataContainer<std::vector<double>>>::iterator it; + for(it = subLabelData.begin(); it != subLabelData.end(); ++it) + { + std::string subLabel = it->first; + DataContainer<std::vector<double>>& data = it->second; + + drawSubGraph (subLabel, data, ofRectangle(state->positionAndSize.x, + state->positionAndSize.y + subLabelY, + state->positionAndSize.width, + heightBetweenSubLabels)); + // Draw label and background + drawTextLabel(subLabel, ofVec2f(state->positionAndSize.x + state->positionAndSize.width, + state->positionAndSize.y + subLabelY), + ofColor(100, 100, 100), ofColor(textColor), TextAlignment::RIGHT, false); + + + // Draw max value + drawTextLabel(ofToString(data.maxValue), + ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2, + state->positionAndSize.y + subLabelY), + ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, false); + + // Increment Y position + subLabelY += heightBetweenSubLabels; + + // Draw min value + // Could show actually found min value + drawTextLabel(ofToString((data.minValue < 0) ? -data.maxValue : 0), + ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2, + state->positionAndSize.y + subLabelY), + ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, true); + + // Draw Line at bottom of graph + ofSetLineWidth(2.0); + ofSetColor (180,180,180); + ofDrawLine(state->positionAndSize.x, state->positionAndSize.y + subLabelY, + state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y + subLabelY); + } + } + + uint32_t getNumSubGraphs ( void ) const + { + return subLabelData.size(); + } +protected: + std::map <std::string, DataContainer<std::vector<double>>> subLabelData; +}; + +#endif /* RealTimeGraph_h */ diff --git a/examples/ofx/Bitalino_rapidmix/rapidVisualizer/ScopeWithHistory.hpp b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/ScopeWithHistory.hpp new file mode 100644 index 0000000..60ab23e --- /dev/null +++ b/examples/ofx/Bitalino_rapidmix/rapidVisualizer/ScopeWithHistory.hpp @@ -0,0 +1,184 @@ +// +// ScopeWithHistory.hpp +// RapidVisualizerOSC +// +// Created by James on 12/11/2017. +// +// + +#ifndef ScopeWithHistory_h +#define ScopeWithHistory_h + +#include <stdio.h> +#include "Graph.hpp" + +class ScopeWithHistory : public Graph +{ +public: + ScopeWithHistory ( GraphState* state ) : Graph (state) + { + // + } + ~ScopeWithHistory ( void ) + { + // + } + void addData ( std::string subLabel, std::vector<double>& data ) + { + if (data.size() < state->historySize) + { + //FIXME: can be sped up by using the result of this search instead of accessing by[] again + if ( subLabelData.find(subLabel) == subLabelData.end() ) { + // not found + DataContainer<std::vector<double>> container; + container.labelData.resize(state->historySize); + std::fill(container.labelData.begin(), container.labelData.end(), 0.0); + subLabelData[subLabel] = container; + } + DataContainer<std::vector<double>>& dataRef = subLabelData[subLabel]; + std::vector<double>& referencedList = dataRef.labelData; + while (referencedList.size() >= state->historySize) + { + referencedList.pop_back(); + } + for (int32_t i = data.size()-1; i >= 0; --i) + { + double val = data[i]; + if (val < dataRef.minValue) + dataRef.minValue = val; + if (val > dataRef.maxValue) + dataRef.maxValue = val; + if (fabs(val) > dataRef.maxValue) + dataRef.maxValue = fabs(val); + if (referencedList.size() + data.size() >= state->historySize) + { + referencedList[dataRef.iteratorPos] = val; + dataRef.iteratorPos = (dataRef.iteratorPos + data.size()) % state->historySize; + } else { + referencedList.insert(referencedList.begin(), val); + } + } + } + } + void updateRep ( void ) + { + // + } + void drawSubGraph ( std::string subLabel, DataContainer<std::vector<double>>& data, ofRectangle subLabelRect ) + { + double + minIn = 0, + minOut = 0, + maxOut = -subLabelRect.height, + startPosY = subLabelRect.height, + pointDistance = subLabelRect.width/data.labelData.size(), + separation = pointDistance/2; + //halfSeparation = separation/2; + bool drawZeroSep = false; + + if (data.minValue < 0) + { // Add negative part + startPosY = subLabelRect.height/2; + minIn = -data.maxValue; + minOut = subLabelRect.height/2; + maxOut /= 2; + drawZeroSep = true; + } + + ofBeginShape(); + ofFill(); + ofVertex(subLabelRect.x, subLabelRect.y + startPosY); + double output = mapVals(data.labelData.front(), minIn, data.maxValue, minOut, maxOut ); + ofVertex(subLabelRect.x, subLabelRect.y + startPosY + output); + uint32_t i = 0; + for (double d : data.labelData) + { + output = mapVals(d, minIn, data.maxValue, minOut, maxOut ); + ofSetColor (graphColor); + + ofVertex(subLabelRect.x + pointDistance * i + separation, subLabelRect.y + startPosY + output); + //ofDrawRectangle(subLabelRect.x + barSize * i + halfSeparation, subLabelRect.y + startPosY, barSize - separation, output ); + ++i; + + } + output = mapVals(data.labelData.back(), minIn, data.maxValue, minOut, maxOut ); + ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY + output); + ofVertex(subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY); + ofEndShape(); + + if (drawZeroSep) + { + ofSetLineWidth(1.25); + ofSetColor (175,150,150); + ofDrawLine(subLabelRect.x, subLabelRect.y + startPosY, + subLabelRect.x + subLabelRect.width, subLabelRect.y + startPosY); + } + } + void update ( void ) + { + // + } + + void reset ( void ) + { + subLabelData.clear(); + } + + void draw ( void ) + { + uint32_t numElements = subLabelData.size(); + uint16_t heightBetweenSubLabels = state->positionAndSize.height/numElements; + uint16_t subLabelY = 0; + + ofSetColor (255,255,255); + ofDrawLine(state->positionAndSize.x, state->positionAndSize.y, + state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y); + + std::map<std::string, DataContainer<std::vector<double>>>::iterator it; + for(it = subLabelData.begin(); it != subLabelData.end(); ++it) + { + std::string subLabel = it->first; + DataContainer<std::vector<double>>& data = it->second; + + drawSubGraph (subLabel, data, ofRectangle(state->positionAndSize.x, + state->positionAndSize.y + subLabelY, + state->positionAndSize.width, + heightBetweenSubLabels)); + // Draw label and background + drawTextLabel(subLabel, ofVec2f(state->positionAndSize.x + state->positionAndSize.width, + state->positionAndSize.y + subLabelY), + ofColor(100, 100, 100), ofColor(textColor), TextAlignment::RIGHT, false); + + + // Draw max value + drawTextLabel(ofToString(data.maxValue), + ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2, + state->positionAndSize.y + subLabelY), + ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, false); + + // Increment Y position + subLabelY += heightBetweenSubLabels; + + // Draw min value + // Show actual min value? + drawTextLabel(ofToString((data.minValue < 0) ? -data.maxValue : 0), + ofVec2f(state->positionAndSize.x + state->positionAndSize.width/2, + state->positionAndSize.y + subLabelY), + ofColor(50, 50, 50), ofColor(255, 255, 255), TextAlignment::CENTER, true); + + // Draw Line at bottom of graph + ofSetLineWidth(2.0); + ofSetColor (180,180,180); + ofDrawLine(state->positionAndSize.x, state->positionAndSize.y + subLabelY, + state->positionAndSize.x + state->positionAndSize.width, state->positionAndSize.y + subLabelY); + } + } + uint32_t getNumSubGraphs ( void ) const + { + return subLabelData.size(); + } +protected: + std::map <std::string, DataContainer<std::vector<double>>> subLabelData; +}; + +#endif /* ScopeWithHistory_h */ -- GitLab