#ifndef PLOT_H #define PLOT_H #include #include "Axes.h" #include "Data.h" #include /** describes a plot-setup */ struct PlotParameters { AxesX xAxes; AxesY yAxes; int w; int h; /** helper method */ Point2 getPoint(const typename Data::KeyVal& kv) const { const float x1 = xAxes.convert(kv.key); const float y1 = yAxes.convert(kv.val); return Point2(x1, y1); } }; /** interface for all plots */ class Plot { protected: Data data; QColor bg = QColor(255,255,255,128); public: virtual ~Plot() {;} void render(QPainter& p, const PlotParameters& params) { // maybe do something here? renderSub(p, params); } Data& getData() {return data;} Range getKeyRange() const {return data.getKeyRange();} Range getValueRange() const {return data.getValueRange();} protected: /** subclasses must render themselves here */ virtual void renderSub(QPainter& p, const PlotParameters& params) = 0; }; /** combine several plots (several lines, points, ...) together into one plot */ class PlotContainer { private: PlotParameters params; std::vector plots; public: /** ctor */ PlotContainer() { ; } AxesX& getAxesX() {return params.xAxes;} AxesY& getAxesY() {return params.yAxes;} Range overwriteRangeKey = Range(0,0); Range overwriteRangeVal = Range(0,0); void setValRange(const Range& range) {overwriteRangeVal = range;} void setKeyRange(const Range& range) {overwriteRangeKey = range;} void resize(const int w, const int h) { params.w = w; params.h = h; } void addPlot(Plot* plt) { plots.push_back(plt); } void render(QPainter& p) { setupAxes(); QColor bg(255,255,255,192); p.fillRect(0,0,params.w,params.h,bg); p.setPen(Qt::black); p.drawRect(0,0,params.w-1,params.h-1); for (Plot* plt : plots) { plt->render(p, params); } } void setupAxes() { params.xAxes.setPixels(params.w); params.yAxes.setPixels(params.h); Range keyRange(+INFINITY,-INFINITY); Range valRange(+INFINITY,-INFINITY); if (overwriteRangeKey.isValid()) {keyRange.adjust(overwriteRangeKey);} if (overwriteRangeVal.isValid()) {valRange.adjust(overwriteRangeVal);} /** calculate min/max for both x and y axis */ for (Plot* plt : plots) { if (!overwriteRangeKey.isValid()) {keyRange.adjust(plt->getKeyRange());} if (!overwriteRangeVal.isValid()) {valRange.adjust(plt->getValueRange());} } valRange.scale(1.1); params.xAxes.setRange(keyRange); params.yAxes.setRange(valRange); } }; class LinePlot : public Plot { private: QColor lineColor = QColor(0,0,255); public: void setColor(const QColor c) { this->lineColor = c; } protected: void renderSub(QPainter& p , const PlotParameters& params) override { p.setPen(lineColor); for (int i = 0; i < (int) data.size()-1; ++i) { const typename Data::KeyVal kv1 = data[i+0]; const typename Data::KeyVal kv2 = data[i+1]; const Point2 p1 = params.getPoint(kv1); const Point2 p2 = params.getPoint(kv2); p.drawLine(p1.x, p1.y, p2.x, p2.y); } } }; class PointPlot : public Plot { private: QColor pointColor = QColor(0,0,255); float pointSize = 4; public: void setColor(const QColor c) { this->pointColor = c; } void setPointSize(const float size) { this->pointSize = size; } protected: void renderSub(QPainter& p , const PlotParameters& params) override { p.setPen(Qt::NoPen); p.setBrush(pointColor); for (int i = 0; i < (int) data.size(); ++i) { const typename Data::KeyVal kv1 = data[i+0]; const Point2 p1 = params.getPoint(kv1); p.drawEllipse(p1.x, p1.y, pointSize, pointSize); } } }; #endif // PLOT_H