1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
// This file is part of fityk program. Copyright 2001-2013 Marcin Wojdyr
// Licence: GNU General Public License ver. 2+
#ifndef FITYK_WX_PLOT_H_
#define FITYK_WX_PLOT_H_
#include <limits.h>
#include <vector>
#include <wx/config.h>
#include "fityk/fityk.h" // Point
#include "fityk/common.h" // iround()
#include "uplot.h" // BufferedPanel
#include "cmn.h" // compatibility with wx2.8 (defined wxPenStyle, etc.)
// convention: lowercase coordinates of point are real values,
// and uppercase ones are coordinates of point on screen (integers).
// INT_MIN, given as coordinate, is invalid value, means "cancel drawing"
namespace fityk { class Model; class Data; struct Rect; }
using fityk::Point;
class wxPoint2DDouble;
inline int get_pixel_width(wxDC const& dc)
{
int w;
dc.GetClippingBox(NULL, NULL, &w, NULL);
//if (w != 0) printf("Clipping On (width)\n");
return w != 0 ? w : dc.GetSize().GetWidth();
}
inline int get_pixel_height(wxDC const& dc)
{
int h;
dc.GetClippingBox(NULL, NULL, NULL, &h);
//if (h != 0) printf("Clipping On (height)\n");
return h != 0 ? h : dc.GetSize().GetHeight();
}
/// convertion between pixels and logical values
class Scale
{
public:
double scale, origin;
bool logarithm, reversed;
Scale() : scale(1.), origin(0.), logarithm(false), reversed(false) {}
/// value -> pixel
int px(double val) const { return iround(px_d(val)); }
inline double px_d(double val) const;
/// pixel -> value
inline double val(int px) const;
// Returns the same value as val(), but rounded in a smart way,
// so when the number is formatted with "%.12g", it is not too long.
double valr(int px) const;
// set scale using minimum and maximum logical values and width/height
// of the screen in pixels.
// In case of y scale, where pixel=0 is at the top, m and M are switched
void set(double m, double M, int pixels);
private:
static int inf_px(double t) { return t > 0 ? SHRT_MAX : SHRT_MIN; }
};
double Scale::px_d(double val) const
{
if (logarithm) {
if (val <= 0)
return inf_px(-scale);
val = log(val);
}
double t = (val - origin) * scale;
return fabs(t) < SHRT_MAX ? t : (double) inf_px(t);
}
double Scale::val(int px) const
{
double a = px / scale + origin;
return logarithm ? exp(a) : a;
}
class Overlay
{
public:
enum Mode
{
kNone,
kRect,
kLinearDraft,
kPeakDraft,
kSigmoidDraft,
kFunction,
kCrossHair,
kVLine,
kHLine,
kVRange,
kHRange
};
Overlay(BufferedPanel *panel) : panel_(panel), mode_(kNone),
color_(192,192,192) {}
void start_mode(Mode m, int x1, int y1) { mode_=m; x1_=x2_=x1; y1_=y2_=y1; }
void switch_mode(Mode m) { mode_=m; }
void change_pos(int x2,int y2)
{ x2_=x2; y2_=y2; if (mode_!=kNone) draw_overlay(); }
void draw_overlay();
void draw_lines(int n, wxPoint points[]);
Mode mode() const { return mode_; }
void bg_color_updated(const wxColour& bg);
private:
BufferedPanel *panel_;
Mode mode_;
wxColour color_;
int x1_, x2_, y1_, y2_;
};
/// This class has no instances, MainPlot and AuxPlot are derived from it
/// It knows how to draw on wxDC. Note that wxDC:SetClippingRegion() should be
/// used together with wxDC::SetDeviceOrigin(). Clipping box is used only in
/// get_pixel_width() and get_pixel_height() functions.
/// When plotting a curve, values in each x from 0 to get_pixel_width() is
/// calculated.
class FPlot : public BufferedPanel
{
public:
FPlot(wxWindow *parent);
virtual ~FPlot();
void set_font(wxDC &dc, wxFont const& font);
void set_scale(int pixel_width, int pixel_height);
int get_special_point_at_pointer(wxMouseEvent& event);
Scale & get_x_scale() { return xs; }
Scale & get_y_scale() { return ys; }
virtual void save_settings(wxConfigBase *cf) const;
virtual void read_settings(wxConfigBase *cf);
void set_magnification(int m) { pen_width = m > 0 ? m : 1; }
void draw_vertical_lines_on_overlay(int X1, int X2);
virtual void set_bg_color(wxColour const& c);
protected:
Scale xs, ys;
Overlay overlay;
// properties stored in config
int pen_width;
wxColour activeDataCol, inactiveDataCol, xAxisCol;
wxFont ticsFont;
int point_radius;
bool line_between_points;
bool draw_sigma;
bool x_axis_visible, y_axis_visible, xtics_visible, ytics_visible,
xminor_tics_visible, yminor_tics_visible;
bool x_grid, y_grid;
int x_max_tics, y_max_tics, x_tic_size, y_tic_size;
int downX, downY;
std::vector<wxPoint> special_points; //used to mark positions of peak tops
wxWindow *esc_source_; // temporary source of OnKeyDown() events
void draw_xtics (wxDC& dc, fityk::Rect const& v, bool set_pen=true);
void draw_ytics (wxDC& dc, fityk::Rect const &v, bool set_pen=true);
double get_max_abs_y(double (*compute_y)(std::vector<Point>::const_iterator,
fityk::Model const*),
std::vector<Point>::const_iterator first,
std::vector<Point>::const_iterator last,
fityk::Model const* model);
void draw_data (wxDC& dc,
double (*compute_y)(std::vector<Point>::const_iterator,
fityk::Model const*),
fityk::Data const* data,
fityk::Model const* model,
wxColour const& color = wxNullColour,
wxColour const& inactive_color = wxNullColour,
int Y_offset = 0,
bool cumulative=false);
// if connect is true: connect, otherwise disconnect;
// connect to the currently focused window and handle wxEVT_KEY_DOWN
// event: if Esc is pressed call cancel_action().
void connect_esc_to_cancel(bool connect);
virtual void cancel_action() {}
// handler used by connect_esc_to_cancel()
void OnKeyDown(wxKeyEvent& event);
private:
void draw_data_by_activity(wxDC& dc, wxPoint2DDouble *pp,
const std::vector<bool>& aa, bool state);
};
#endif
|