diff options
Diffstat (limited to 'wx+/graph.h')
-rw-r--r-- | wx+/graph.h | 137 |
1 files changed, 86 insertions, 51 deletions
diff --git a/wx+/graph.h b/wx+/graph.h index 8f816b08..fe008a38 100644 --- a/wx+/graph.h +++ b/wx+/graph.h @@ -7,13 +7,15 @@ #ifndef WX_PLOT_HEADER_2344252459 #define WX_PLOT_HEADER_2344252459 +#include <map> #include <vector> #include <memory> #include <wx/panel.h> -#include <wx/dcbuffer.h> +//#include <wx/dcbuffer.h> #include <zen/string_tools.h> +#include <zen/optional.h> -//simple 2D graph as wxPanel specialization +//elegant 2D graph as wxPanel specialization namespace zen { @@ -21,62 +23,90 @@ namespace zen Example: //init graph (optional) m_panelGraph->setAttributes(Graph2D::MainAttributes(). - setLabelX(Graph2D::POSLX_BOTTOM, 20, std::make_shared<LabelFormatterTimeElapsed>()). - setLabelY(Graph2D::POSLY_RIGHT, 60, std::make_shared<LabelFormatterBytes>())); + setLabelX(Graph2D::X_LABEL_BOTTOM, 20, std::make_shared<LabelFormatterTimeElapsed>()). + setLabelY(Graph2D::Y_LABEL_RIGHT, 60, std::make_shared<LabelFormatterBytes>())); //set graph data - std::shared_ptr<GraphData> graphDataBytes = ... - m_panelGraph->setData(graphDataBytes, Graph2D::CurveAttributes().setLineWidth(2).setColor(wxColor(0, 192, 0))); + std::shared_ptr<CurveData> curveDataBytes = ... + m_panelGraph->setCurve(curveDataBytes, Graph2D::CurveAttributes().setLineWidth(2).setColor(wxColor(0, 192, 0))); */ -//------------------------------------------------------------------------------------------------------------ -struct GraphData +struct CurvePoint { - virtual ~GraphData() {} - virtual double getValue (double x) const = 0; - virtual double getXBegin() const = 0; - virtual double getXEnd () const = 0; //upper bound for x, getValue() is NOT evaluated at this position! Similar to std::vector::end() + CurvePoint() : x(0), y(0) {} + CurvePoint(double xVal, double yVal) : x(xVal), y(yVal) {} + double x; + double y; }; +inline bool operator==(const CurvePoint& lhs, const CurvePoint& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } +inline bool operator!=(const CurvePoint& lhs, const CurvePoint& rhs) { return !(lhs == rhs); } +struct CurveData +{ + virtual ~CurveData() {} -//reference data implementation -class RangeData : public GraphData + virtual std::pair<double, double> getRangeX() const = 0; + virtual void getPoints(double minX, double maxX, int pixelWidth, + std::vector<CurvePoint>& points) const = 0; //points outside the draw area are automatically trimmed! +}; + +//special curve types: +struct ContinuousCurveData : public CurveData { -public: - std::vector<double>& refData() { return data; } + virtual double getValue(double x) const = 0; private: - virtual double getValue(double x) const - { - const size_t pos = static_cast<size_t>(x); - return pos < data.size() ? data[pos] : 0; - } - virtual double getXBegin() const { return 0; } - virtual double getXEnd() const { return data.size(); } //example: two-element range is accessible within [0, 2) + virtual void getPoints(double minX, double maxX, int pixelWidth, std::vector<CurvePoint>& points) const final; +}; - std::vector<double> data; +struct SparseCurveData : public CurveData +{ + SparseCurveData(bool addSteps = false) : addSteps_(addSteps) {} //addSteps: add points to get a staircase effect or connect points via a direct line + + virtual Opt<CurvePoint> getLessEq (double x) const = 0; + virtual Opt<CurvePoint> getGreaterEq(double x) const = 0; + +private: + virtual void getPoints(double minX, double maxX, int pixelWidth, std::vector<CurvePoint>& points) const final; + bool addSteps_; }; -/* -//reference data implementation -class VectorData : public GraphData +struct ArrayCurveData : public SparseCurveData { -public: - operator std::vector<double>& () { return data; } + virtual double getValue(size_t pos) const = 0; + virtual size_t getSize() const = 0; private: - virtual double getValue(double x) const + virtual std::pair<double, double> getRangeX() const final { const size_t sz = getSize(); return std::make_pair(0.0, sz == 0 ? 0.0 : sz - 1.0); } + + virtual Opt<CurvePoint> getLessEq(double x) const final { - const size_t pos = static_cast<size_t>(x); - return pos < data.size() ? data[pos] : 0; + const size_t sz = getSize(); + const size_t pos = std::min<ptrdiff_t>(std::floor(x), sz - 1); //[!] expect unsigned underflow if empty! + if (pos < sz) + return CurvePoint(pos, getValue(pos)); + return NoValue(); } - virtual double getXBegin() const { return 0; } - virtual double getXEnd() const { return data.size(); } //example: two-element range is accessible within [0, 2) - std::vector<double> data; + virtual Opt<CurvePoint> getGreaterEq(double x) const final + { + const size_t pos = std::max<ptrdiff_t>(std::ceil(x), 0); //[!] use std::max with signed type! + if (pos < getSize()) + return CurvePoint(pos, getValue(pos)); + return NoValue(); + } +}; + +struct VectorCurveData : public ArrayCurveData +{ + std::vector<double>& refData() { return data; } +private: + virtual double getValue(size_t pos) const final { return pos < data.size() ? data[pos] : 0; } + virtual size_t getSize() const final { return data.size(); } + std::vector<double> data; }; -*/ //------------------------------------------------------------------------------------------------------------ + struct LabelFormatter { virtual ~LabelFormatter() {} @@ -106,16 +136,8 @@ extern const wxEventType wxEVT_GRAPH_SELECTION; struct SelectionBlock { - struct Point - { - Point() : x(0), y(0) {} - Point(double xVal, double yVal) : x(xVal), y(yVal) {} - double x; - double y; - }; - - Point from; - Point to; + CurvePoint from; + CurvePoint to; }; class GraphSelectEvent : public wxCommandEvent @@ -135,8 +157,8 @@ typedef void (wxEvtHandler::*GraphSelectEventFunction)(GraphSelectEvent&); #define GraphSelectEventHandler(func) \ (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GraphSelectEventFunction, &func) - //------------------------------------------------------------------------------------------------------------ + class Graph2D : public wxPanel { public: @@ -168,8 +190,8 @@ public: int lineWidth; }; - void setData(const std::shared_ptr<GraphData>& data, const CurveAttributes& ca = CurveAttributes()); - void addData(const std::shared_ptr<GraphData>& data, const CurveAttributes& ca = CurveAttributes()); + void setCurve(const std::shared_ptr<CurveData>& data, const CurveAttributes& ca = CurveAttributes()); + void addCurve(const std::shared_ptr<CurveData>& data, const CurveAttributes& ca = CurveAttributes()); enum PosLabelY { @@ -185,6 +207,14 @@ public: X_LABEL_NONE }; + enum PosCorner + { + CORNER_TOP_LEFT, + CORNER_TOP_RIGHT, + CORNER_BOTTOM_LEFT, + CORNER_BOTTOM_RIGHT, + }; + enum SelMode { SELECT_NONE, @@ -238,6 +268,8 @@ public: return *this; } + MainAttributes& setCornerText(const wxString& txt, PosCorner pos) { cornerTexts[pos] = txt; return *this; } + MainAttributes& setSelectionMode(SelMode mode) { mouseSelMode = mode; return *this; } private: @@ -261,6 +293,8 @@ public: int yLabelWidth; std::shared_ptr<LabelFormatter> labelFmtY; + std::map<PosCorner, wxString> cornerTexts; + SelMode mouseSelMode; }; void setAttributes(const MainAttributes& newAttr) { attr = newAttr; Refresh(); } @@ -311,8 +345,9 @@ private: std::unique_ptr<wxBitmap> doubleBuffer; - typedef std::vector<std::pair<std::shared_ptr<GraphData>, CurveAttributes>> GraphList; - GraphList curves_; + typedef std::vector<std::pair<std::shared_ptr<CurveData>, CurveAttributes>> CurveList; + CurveList curves_; + wxFont labelFont; //perf!!! generating the font is *very* expensive! don't do this repeatedly in Graph2D::render()! }; } |