1 #ifndef RAMMING_CHART_H_
2 #define RAMMING_CHART_H_
3 
4 #include <vector>
5 #include <wx/wxprec.h>
6 #ifndef WX_PRECOMP
7     #include <wx/wx.h>
8 #endif
9 
10 wxDECLARE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent);
11 
12 
13 class Chart : public wxWindow {
14 
15 public:
Chart(wxWindow * parent,wxRect rect,const std::vector<std::pair<float,float>> & initial_buttons,int ramming_speed_size,float sampling,int scale_unit=10)16     Chart(wxWindow* parent, wxRect rect,const std::vector<std::pair<float,float>>& initial_buttons,int ramming_speed_size, float sampling, int scale_unit=10) :
17         wxWindow(parent,wxID_ANY,rect.GetTopLeft(),rect.GetSize()),
18         scale_unit(scale_unit), legend_side(5*scale_unit)
19     {
20         SetBackgroundStyle(wxBG_STYLE_PAINT);
21         m_rect = wxRect(wxPoint(legend_side,0),rect.GetSize()-wxSize(legend_side,legend_side));
22         visible_area = wxRect2DDouble(0.0, 0.0, sampling*ramming_speed_size, 20.);
23         m_buttons.clear();
24         if (initial_buttons.size()>0)
25             for (const auto& pair : initial_buttons)
26                 m_buttons.push_back(wxPoint2DDouble(pair.first,pair.second));
27         recalculate_line();
28     }
set_xy_range(float x,float y)29     void set_xy_range(float x,float y) {
30         x = int(x/0.5) * 0.5;
31         if (x>=0) visible_area.SetRight(x);
32         if (y>=0) visible_area.SetBottom(y);
33         recalculate_line();
34     }
get_volume() const35     float get_volume() const { return m_total_volume; }
get_time() const36     float get_time()   const { return visible_area.m_width; }
37 
38     std::vector<float> get_ramming_speed(float sampling) const; //returns sampled ramming speed
39     std::vector<std::pair<float,float>> get_buttons() const; // returns buttons position
40 
41     void draw();
42 
43     void mouse_clicked(wxMouseEvent& event);
44     void mouse_right_button_clicked(wxMouseEvent& event);
45     void mouse_moved(wxMouseEvent& event);
46     void mouse_double_clicked(wxMouseEvent& event);
mouse_left_window(wxMouseEvent &)47     void mouse_left_window(wxMouseEvent&) { m_dragged = nullptr; }
mouse_released(wxMouseEvent &)48     void mouse_released(wxMouseEvent&)    { m_dragged = nullptr; }
paint_event(wxPaintEvent &)49     void paint_event(wxPaintEvent&) { draw(); }
50     DECLARE_EVENT_TABLE()
51 
52 
53 
54 
55 private:
56     static const bool fixed_x = true;
57     static const bool splines = true;
58     static const bool manual_points_manipulation = false;
59     static const int side = 10; // side of draggable button
60 
61     const int scale_unit;
62     int legend_side;
63 
64     class ButtonToDrag {
65     public:
operator <(const ButtonToDrag & a) const66         bool operator<(const ButtonToDrag& a) const { return m_pos.m_x < a.m_pos.m_x; }
ButtonToDrag(wxPoint2DDouble pos)67         ButtonToDrag(wxPoint2DDouble pos) : m_pos{pos} {};
get_pos() const68         wxPoint2DDouble get_pos() const { return m_pos; }
move(double x,double y)69         void move(double x,double y) { m_pos.m_x+=x; m_pos.m_y+=y; }
70     private:
71         wxPoint2DDouble m_pos;              // position in math coordinates
72     };
73 
74 
75 
math_to_screen(const wxPoint2DDouble & math) const76     wxPoint math_to_screen(const wxPoint2DDouble& math) const {
77         wxPoint screen;
78         screen.x = (math.m_x-visible_area.m_x) * (m_rect.GetWidth()  / visible_area.m_width  );
79         screen.y = (math.m_y-visible_area.m_y) * (m_rect.GetHeight() / visible_area.m_height );
80         screen.y *= -1;
81         screen += m_rect.GetLeftBottom();
82         return screen;
83     }
screen_to_math(const wxPoint & screen) const84     wxPoint2DDouble screen_to_math(const wxPoint& screen) const {
85         wxPoint2DDouble math = screen;
86         math -= m_rect.GetLeftBottom();
87         math.m_y *= -1;
88         math.m_x *= visible_area.m_width   / m_rect.GetWidth();    // scales to [0;1]x[0,1]
89         math.m_y *= visible_area.m_height / m_rect.GetHeight();
90         return (math+visible_area.GetLeftTop());
91     }
92 
which_button_is_clicked(const wxPoint & point) const93     int which_button_is_clicked(const wxPoint& point) const {
94         if (!m_rect.Contains(point))
95             return -1;
96         for (unsigned int i=0;i<m_buttons.size();++i) {
97             wxRect rect(math_to_screen(m_buttons[i].get_pos())-wxPoint(side/2.,side/2.),wxSize(side,side)); // bounding rectangle of this button
98             if ( rect.Contains(point) )
99                 return i;
100         }
101         return (-1);
102     }
103 
104 
105     void recalculate_line();
106     void recalculate_volume();
107 
108 
109     wxRect m_rect;                  // rectangle on screen the chart is mapped into (screen coordinates)
110     wxPoint m_previous_mouse;
111     std::vector<ButtonToDrag> m_buttons;
112     std::vector<int> m_line_to_draw;
113     wxRect2DDouble visible_area;
114     ButtonToDrag* m_dragged = nullptr;
115     float m_total_volume = 0.f;
116 
117 };
118 
119 
120 #endif // RAMMING_CHART_H_