author | Francesco Abbate <francesco.bbt@gmail.com> | 2013年02月04日 21:46:49 +0100 |
---|---|---|
committer | Francesco Abbate <francesco.bbt@gmail.com> | 2013年02月04日 21:46:49 +0100 |
commit | 858c66cac8902ad7fd32d10ae82bb885f9774904 (patch) | |
tree | d9d5e118f3cc21336da56263470a6ffd3462f47d | |
parent | fe5cea0c67ac178d6476beb64f2bd5fcf4acb0f0 (diff) | |
parent | 9b63ca608ee573a2588ad14a3a46a5ca9f00f9a2 (diff) | |
download | gsl-shell-858c66cac8902ad7fd32d10ae82bb885f9774904.tar.gz |
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | agg-plot/Makefile | 2 | ||||
-rw-r--r-- | agg-plot/factor_labels.h | 28 | ||||
-rw-r--r-- | agg-plot/lua-plot-cpp.h | 4 | ||||
-rw-r--r-- | agg-plot/lua-plot.cpp | 54 | ||||
-rw-r--r-- | agg-plot/plot-auto.cpp | 114 | ||||
-rw-r--r-- | agg-plot/plot-auto.h | 134 | ||||
-rw-r--r-- | agg-plot/plot.cpp | 660 | ||||
-rw-r--r-- | agg-plot/plot.h | 645 | ||||
-rw-r--r-- | agg-plot/units.h | 1 | ||||
-rw-r--r-- | agg-plot/utils.h | 4 | ||||
-rw-r--r-- | fox-gui/lua_plot_window.cpp | 2 | ||||
-rw-r--r-- | iter.lua | 14 | ||||
-rw-r--r-- | matrix.lua | 23 | ||||
-rwxr-xr-x | scripts/dos2unix.py | 34 | ||||
-rw-r--r-- | scripts/enum2lua.py | 12 |
diff --git a/.gitignore b/.gitignore index 5ddc7521..83d1718f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.dll luajit2/lib/vmdef.lua *~ +*.sublime* gsl-shell gsl-shell.exe .deps diff --git a/agg-plot/Makefile b/agg-plot/Makefile index f68b3cd8..5f2c1a48 100644 --- a/agg-plot/Makefile +++ b/agg-plot/Makefile @@ -39,7 +39,7 @@ endif INCLUDES += $(FREETYPE_INCLUDES) $(AGG_INCLUDES) -I$(GSH_BASE_DIR) -I$(GSH_BASE_DIR)/lua-gsl -I$(LUADIR)/src -I$(GSH_BASE_DIR)/cpp-utils -AGGPLOT_SRC_FILES = $(PLATSUP_SRC_FILES) printf_check.cpp fonts.cpp gamma.cpp agg_font_freetype.cpp utils.cpp units.cpp colors.cpp markers.cpp draw_svg.cpp canvas_svg.cpp lua-draw.cpp lua-text.cpp text.cpp agg-parse-trans.cpp window_registry.cpp window.cpp lua-plot.cpp canvas-window.cpp bitmap-plot.cpp lua-graph.cpp +AGGPLOT_SRC_FILES = $(PLATSUP_SRC_FILES) printf_check.cpp fonts.cpp gamma.cpp agg_font_freetype.cpp plot.cpp plot-auto.cpp utils.cpp units.cpp colors.cpp markers.cpp draw_svg.cpp canvas_svg.cpp lua-draw.cpp lua-text.cpp text.cpp agg-parse-trans.cpp window_registry.cpp window.cpp lua-plot.cpp canvas-window.cpp bitmap-plot.cpp lua-graph.cpp AGGPLOT_OBJ_FILES := $(AGGPLOT_SRC_FILES:%.cpp=%.o) diff --git a/agg-plot/factor_labels.h b/agg-plot/factor_labels.h new file mode 100644 index 00000000..27f6ef47 --- /dev/null +++ b/agg-plot/factor_labels.h @@ -0,0 +1,28 @@ +#include "agg_array.h" +#include "utils.h" +#include "strpp.h" + +class factor_labels +{ +public: + factor_labels(double delta): m_mark_delta(delta) {} + + double mark(int k) const { return m_mark_index[k] * m_mark_delta; } + const char *label_text(int k) const { return m_label_text[k]->cstr(); } + int labels_number() const { return m_label_text.size(); } + + void add_mark(int index, const char *text) + { + m_mark_index.add(index); + if (text) + { + str* text_str = new str(text); + m_label_text.add(text_str); + } + } + +private: + double m_mark_delta; + agg::pod_bvector<short> m_mark_index; + ptr_list<str> m_label_text; +}; diff --git a/agg-plot/lua-plot-cpp.h b/agg-plot/lua-plot-cpp.h index 5f92e499..0aa7bca4 100644 --- a/agg-plot/lua-plot-cpp.h +++ b/agg-plot/lua-plot-cpp.h @@ -10,7 +10,7 @@ extern "C" { #include "plot-auto.h" #include "resource-manager.h" -typedef plot<manage_owner> sg_plot; -typedef plot_auto<manage_owner> sg_plot_auto; +typedef plot sg_plot; +typedef plot_auto sg_plot_auto; #endif diff --git a/agg-plot/lua-plot.cpp b/agg-plot/lua-plot.cpp index 42961d46..5053dbaa 100644 --- a/agg-plot/lua-plot.cpp +++ b/agg-plot/lua-plot.cpp @@ -70,6 +70,8 @@ static int plot_ylab_angle_get (lua_State *L); static int plot_set_categories (lua_State *L); static int plot_set_legend (lua_State *L); static int plot_get_legend (lua_State *L); +static int plot_xaxis_hol_set (lua_State *L); +static int plot_xaxis_hol_clear(lua_State *L); static int plot_sync_mode_get (lua_State *L); static int plot_sync_mode_set (lua_State *L); @@ -109,6 +111,8 @@ static const struct luaL_Reg plot_methods[] = { {"set_categories", plot_set_categories}, {"set_legend", plot_set_legend}, {"get_legend", plot_get_legend}, + {"set_multi_labels", plot_xaxis_hol_set}, + {"clear_multi_labels", plot_xaxis_hol_clear}, {NULL, NULL} }; @@ -467,6 +471,56 @@ plot_units_get (lua_State *L) return plot_bool_property_get(L, &sg_plot::use_units); } +int plot_xaxis_hol_set (lua_State *L) +{ + sg_plot *p = object_check<sg_plot>(L, 1, GS_PLOT); + double delta = lua_tonumber(L, 2); + + if (!lua_istable(L, 3)) + return luaL_error(L, "expect labels table specification"); + + ptr_list<factor_labels>* hol = p->get_xaxis_hol(); + bool create_hol = (hol == 0); + if (create_hol) + hol = new ptr_list<factor_labels>(); + + factor_labels* fl = new factor_labels(delta); + int n = lua_objlen(L, 3); + for (int k = 1; k <= n; k += 2) + { + lua_rawgeti(L, 3, k); + int idx = lua_tonumber(L, -1); + lua_pop(L, 1); + + lua_rawgeti(L, 3, k + 1); + const char* str = lua_tostring(L, -1); + fl->add_mark(idx, str); + lua_pop(L, 1); + + if (!str) + break; + } + + AGG_LOCK(); + hol->add(fl); + if (create_hol) + p->set_xaxis_hol(hol); + AGG_UNLOCK(); + + plot_update_raw (L, p, 1); + return 0; +} + +int plot_xaxis_hol_clear (lua_State *L) +{ + sg_plot *p = object_check<sg_plot>(L, 1, GS_PLOT); + AGG_LOCK(); + p->set_xaxis_hol(0); + AGG_UNLOCK(); + plot_update_raw (L, p, 1); + return 0; +} + void plot_update_raw (lua_State *L, sg_plot *p, int plot_index) { diff --git a/agg-plot/plot-auto.cpp b/agg-plot/plot-auto.cpp new file mode 100644 index 00000000..e7ae8869 --- /dev/null +++ b/agg-plot/plot-auto.cpp @@ -0,0 +1,114 @@ +#include "plot-auto.h" + +void plot_auto::add(sg_object* vs, agg::rgba8& color, bool outline) +{ + item d(vs, color, outline); + + if (!this->fit_inside(vs)) + { + this->m_bbox_updated = false; + this->m_need_redraw = true; + this->m_enlarged_layer = true; + } + + list<item> *nn = new list<item>(d); + this->m_drawing_queue = list<item>::push_back(this->m_drawing_queue, nn); + + RM::acquire(vs); +} + +void plot_auto::check_bounding_box() +{ + this->calc_bounding_box(); + this->update_units(); + this->m_bbox_updated = true; +} + +void plot_auto::calc_layer_bounding_box(plot_auto::item_list* layer, + opt_rect<double>& rect) +{ + for (unsigned j = 0; j < layer->size(); j++) + { + item& d = (*layer)[j]; + agg::rect_base<double> r; + + d.vs->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); + rect.add<rect_union>(r); + } +} + +void plot_auto::calc_bounding_box() +{ + opt_rect<double> box; + + unsigned n = this->nb_layers(); + for (unsigned j = 0; j < n-1; j++) + { + box.add<rect_union>(this->get_layer(j)->bounding_box()); + } + + calc_layer_bounding_box(this->get_layer(n-1), box); + for (list<item> *t = this->m_drawing_queue; t; t = t->next()) + { + const item& d = t->content(); + agg::rect_base<double> r; + d.vs->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); + box.add<rect_union>(r); + } + + this->m_rect = box; +} + +bool plot_auto::fit_inside(sg_object* obj) const +{ + if (!this->m_bbox_updated || !this->m_rect.is_defined()) + return false; + + agg::rect_base<double> r; + obj->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); + + const agg::rect_base<double>& bb = this->m_rect.rect(); + return bb.hit_test(r.x1, r.y1) && bb.hit_test(r.x2, r.y2); +} + +void plot_auto::set_opt_limits(const opt_rect<double>& r) +{ + if (r.is_defined()) + this->set_limits(r.rect()); + else + this->unset_limits(); +} + +bool plot_auto::push_layer() +{ + bool retval = this->plot::push_layer(); + if (this->m_rect.is_defined()) + this->parent_layer()->set_bounding_box(this->m_rect.rect()); + this->m_bbox_updated = true; + this->m_enlarged_layer = false; + return retval; +} + +bool plot_auto::pop_layer() +{ + bool retval = this->plot::pop_layer(); + if (this->m_enlarged_layer) + this->m_bbox_updated = false; + this->m_enlarged_layer = true; + return retval; +} + +void plot_auto::clear_current_layer() +{ + this->plot::clear_current_layer(); + if (this->m_enlarged_layer) + { + item_list* parent = this->parent_layer(); + if (parent) + set_opt_limits(parent->bounding_box()); + else + this->unset_limits(); + } + this->m_bbox_updated = true; + this->m_enlarged_layer = false; +} diff --git a/agg-plot/plot-auto.h b/agg-plot/plot-auto.h index 52e40de2..a6321840 100644 --- a/agg-plot/plot-auto.h +++ b/agg-plot/plot-auto.h @@ -27,15 +27,13 @@ #include "agg_array.h" #include "agg_basics.h" -template<class resource_manager> -class plot_auto : public plot<resource_manager> { - typedef typename plot<resource_manager>::item item; - typedef typename plot<resource_manager>::item_list item_list; +class plot_auto : public plot { + typedef typename plot::item item; + typedef typename plot::item_list item_list; public: plot_auto() : - plot<resource_manager>(true), - m_bbox_updated(true), m_enlarged_layer(false) + plot(true), m_bbox_updated(true), m_enlarged_layer(false) { }; virtual ~plot_auto() { }; @@ -43,7 +41,7 @@ public: virtual void add(sg_object* vs, agg::rgba8& color, bool outline); virtual void before_draw() { - plot<resource_manager>::before_draw(); + plot::before_draw(); if (!m_bbox_updated) check_bounding_box(); }; @@ -65,126 +63,4 @@ private: bool m_enlarged_layer; }; -template <class RM> -void plot_auto<RM>::add(sg_object* vs, agg::rgba8& color, bool outline) -{ - item d(vs, color, outline); - - if (!this->fit_inside(vs)) - { - this->m_bbox_updated = false; - this->m_need_redraw = true; - this->m_enlarged_layer = true; - } - - list<item> *nn = new list<item>(d); - this->m_drawing_queue = list<item>::push_back(this->m_drawing_queue, nn); - - RM::acquire(vs); -} - -template<class RM> -void plot_auto<RM>::check_bounding_box() -{ - this->calc_bounding_box(); - this->update_units(); - this->m_bbox_updated = true; -} - -template<class RM> -void plot_auto<RM>::calc_layer_bounding_box(plot_auto<RM>::item_list* layer, - opt_rect<double>& rect) -{ - for (unsigned j = 0; j < layer->size(); j++) - { - item& d = (*layer)[j]; - agg::rect_base<double> r; - - d.vs->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); - rect.add<rect_union>(r); - } -} - -template<class RM> -void plot_auto<RM>::calc_bounding_box() -{ - opt_rect<double> box; - - unsigned n = this->nb_layers(); - for (unsigned j = 0; j < n-1; j++) - { - box.add<rect_union>(this->get_layer(j)->bounding_box()); - } - - calc_layer_bounding_box(this->get_layer(n-1), box); - for (list<item> *t = this->m_drawing_queue; t; t = t->next()) - { - const item& d = t->content(); - agg::rect_base<double> r; - d.vs->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); - box.add<rect_union>(r); - } - - this->m_rect = box; -} - -template<class RM> -bool plot_auto<RM>::fit_inside(sg_object* obj) const -{ - if (!this->m_bbox_updated || !this->m_rect.is_defined()) - return false; - - agg::rect_base<double> r; - obj->bounding_box(&r.x1, &r.y1, &r.x2, &r.y2); - - const agg::rect_base<double>& bb = this->m_rect.rect(); - return bb.hit_test(r.x1, r.y1) && bb.hit_test(r.x2, r.y2); -} - -template<class RM> -void plot_auto<RM>::set_opt_limits(const opt_rect<double>& r) -{ - if (r.is_defined()) - this->set_limits(r.rect()); - else - this->unset_limits(); -} - -template<class RM> -bool plot_auto<RM>::push_layer() -{ - bool retval = this->plot<RM>::push_layer(); - if (this->m_rect.is_defined()) - this->parent_layer()->set_bounding_box(this->m_rect.rect()); - this->m_bbox_updated = true; - this->m_enlarged_layer = false; - return retval; -} - -template<class RM> -bool plot_auto<RM>::pop_layer() -{ - bool retval = this->plot<RM>::pop_layer(); - if (this->m_enlarged_layer) - this->m_bbox_updated = false; - this->m_enlarged_layer = true; - return retval; -} - -template<class RM> -void plot_auto<RM>::clear_current_layer() -{ - this->plot<RM>::clear_current_layer(); - if (this->m_enlarged_layer) - { - item_list* parent = this->parent_layer(); - if (parent) - set_opt_limits(parent->bounding_box()); - else - this->unset_limits(); - } - this->m_bbox_updated = true; - this->m_enlarged_layer = false; -} - #endif diff --git a/agg-plot/plot.cpp b/agg-plot/plot.cpp new file mode 100644 index 00000000..95f3f743 --- /dev/null +++ b/agg-plot/plot.cpp @@ -0,0 +1,660 @@ +#include "plot.h" + +static double compute_scale(const agg::trans_affine& m) +{ + return m.scale() / 480.0; +} + +static double +std_line_width(double scale, double w = 1.0) +{ +#if 0 + const double dsf = M_LN10; + double ls = log(scale) / dsf; + return exp(round(ls) * dsf) * w * 1.5; +#else + return w * 1.5; +#endif +} + +void plot::commit_pending_draw() +{ + push_drawing_queue(); + m_need_redraw = false; + m_changes_pending.clear(); +} + +void plot::add(sg_object* vs, agg::rgba8& color, bool outline) +{ + item d(vs, color, outline); + list<item> *new_node = new list<item>(d); + m_drawing_queue = list<item>::push_back(m_drawing_queue, new_node); + RM::acquire(vs); +} + +void plot::push_drawing_queue() +{ + item_list* layer = current_layer(); + for (list<item> *c = m_drawing_queue; c != 0; c = c->next()) + { + layer->add(c->content()); + } + + while (m_drawing_queue) + m_drawing_queue = list<item>::pop(m_drawing_queue); +} + +void plot::clear_drawing_queue() +{ + while (m_drawing_queue) + { + item& d = m_drawing_queue->content(); + RM::dispose(d.vs); + m_drawing_queue = list<item>::pop(m_drawing_queue); + } +} + +static bool area_is_valid(const agg::trans_affine& b) +{ + const double thresold = 40.0; + return (b.sx > thresold && b.sy > thresold); +} + +void plot::draw_virtual_canvas(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) +{ + before_draw(); + draw_legends(canvas, layout); + + if (area_is_valid(layout.plot_area)) + { + draw_axis(canvas, layout, clip); + draw_elements(canvas, layout); + } +}; + +void plot::draw_simple(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) +{ + before_draw(); + draw_axis(canvas, layout, clip); + draw_elements(canvas, layout); +}; + +void plot::draw_element(item& c, canvas_type& canvas, const agg::trans_affine& m) +{ + sg_object& vs = c.content(); + vs.apply_transform(m, 1.0); + + if (c.outline) + canvas.draw_outline(vs, c.color); + else + canvas.draw(vs, c.color); +} + +agg::trans_affine plot::get_model_matrix(const plot_layout& layout) +{ + agg::trans_affine m = m_trans; + trans_affine_compose (m, layout.plot_active_area); + return m; +} + +void plot::clip_plot_area(canvas_type& canvas, const agg::trans_affine& area_mtx) +{ + if (this->clip_is_active()) + { + agg::rect_base<int> clip = rect_of_slot_matrix<int>(area_mtx); + canvas.clip_box(clip); + } +} + +void plot::draw_elements(canvas_type& canvas, const plot_layout& layout) +{ + const agg::trans_affine m = get_model_matrix(layout); + + this->clip_plot_area(canvas, layout.plot_active_area); + + for (unsigned k = 0; k < m_layers.size(); k++) + { + item_list& layer = *(m_layers[k]); + for (unsigned j = 0; j < layer.size(); j++) + { + draw_element(layer[j], canvas, m); + } + } + + canvas.reset_clipping(); +} + +void plot::compute_user_trans() +{ + agg::rect_base<double> r; + + if (m_use_units && m_pad_units) + { + int ixi, ixs, iyi, iys; + double xd, yd; + m_ux.limits(ixi, ixs, xd); + r.x1 = ixi * xd; + r.x2 = ixs * xd; + + m_uy.limits(iyi, iys, yd); + r.y1 = iyi * yd; + r.y2 = iys * yd; + } + else + { + r = m_rect.is_defined() ? m_rect.rect() : agg::rect_base<double>(0.0, 0.0, 1.0, 1.0); + } + + double dx = r.x2 - r.x1, dy = r.y2 - r.y1; + double fx = (dx == 0 ? 1.0 : 1/dx), fy = (dy == 0 ? 1.0 : 1/dy); + this->m_trans = agg::trans_affine(fx, 0.0, 0.0, fy, -r.x1 * fx, -r.y1 * fy); +} + +void plot::draw_grid(const axis_e dir, const units& u, + const agg::trans_affine& user_mtx, + agg::path_storage& ln) +{ + const double eps = 1.0e-3; + const bool isx = (dir == x_axis); + + int jinf = u.begin(), jsup = u.end(); + for (int j = jinf+1; j < jsup; j++) + { + double uq = u.mark_value(j); + double x = (isx ? uq : 0), y = (isx ? 0.0 : uq); + user_mtx.transform(&x, &y); + const double q = (isx ? x : y); + + if (q >= -eps && q <= 1.0 + eps) + { + ln.move_to(isx ? q : 0.0, isx ? 0.0 : q); + ln.line_to(isx ? q : 1.0, isx ? 1.0 : q); + } + } +} + + +double plot::draw_axis_m(axis_e dir, units& u, + const agg::trans_affine& user_mtx, + ptr_list<draw::text>& labels, double scale, + agg::path_storage& mark, agg::path_storage& ln) +{ + const double ppad = double(axis_label_prop_space) / 1000.0; + const double text_label_size = get_default_font_size(text_axis_labels, scale); + const double eps = 1.0e-3; + + // used to store the bounding box of text labels + opt_rect<double> bb; + agg::rect_base<double> r; + + bool isx = (dir == x_axis); + + const axis& ax = get_axis(dir); + double hj = ax.labels_hjustif(), vj = ax.labels_vjustif(); + double langle = ax.labels_angle(); + + category_map::iterator clabels(ax.categories); + units_iterator ulabels(u, ax.format_tag, ax.label_format()); + + label_iterator* ilabels = (ax.use_categories ? (label_iterator*) &clabels : (label_iterator*) &ulabels); + + double uq; + const char* text; + while (ilabels->next(uq, text)) + { + double x = (isx ? uq : 0.0), y = (isx ? 0.0 : uq); + user_mtx.transform(&x, &y); + + double q = (isx ? x : y); + + if (q < -eps || q > 1.0 + eps) + continue; + + draw::text* label = new draw::text(text, text_label_size, hj, vj); + + label->set_point(isx ? q : -ppad, isx ? -ppad : q); + label->angle(langle); + + agg::bounding_rect_single(*label, 0, &r.x1, &r.y1, &r.x2, &r.y2); + bb.add<rect_union>(r); + + labels.add(label); + + mark.move_to(isx ? q : 0.0 , isx ? 0.0 : q); + mark.line_to(isx ? q : -0.01, isx ? -0.01 : q); + } + + this->draw_grid(dir, u, user_mtx, ln); + + double label_size; + if (bb.is_defined()) + { + const agg::rect_base<double>& br = bb.rect(); + label_size = (isx ? br.y2 - br.y1 : br.x2 - br.x1); + } + else + { + label_size = 0.0; + } + + return label_size; +} + +double plot::draw_xaxis_factors(units& u, + const agg::trans_affine& user_mtx, + ptr_list<draw::text>& labels, + ptr_list<factor_labels>* f_labels, double scale, + agg::path_storage& mark, agg::path_storage& ln) +{ + const double text_label_size = get_default_font_size(text_axis_labels, scale); + + const double y_spacing = 0.05; + const unsigned layers_number = f_labels->size(); + double p_lab = - double(layers_number) * y_spacing; + for (unsigned layer = 0; layer < layers_number; layer++) + { + factor_labels* factor = f_labels->at(layer); + for (int k = 0; k < factor->labels_number(); k++) + { + double x_lab_a = factor->mark(k); + double x_lab_b = factor->mark(k+1); + + double x_a = x_lab_a, y_a = 0.0; + user_mtx.transform(&x_a, &y_a); + double q_a = x_a; + + double x_lab = (x_lab_a + x_lab_b) / 2, y_lab = 0.0; + user_mtx.transform(&x_lab, &y_lab); + double q_lab = x_lab; + + mark.move_to(q_a, p_lab); + mark.line_to(q_a, p_lab + y_spacing); + + const char* text = factor->label_text(k); + draw::text* label = new draw::text(text, text_label_size, 0.5, -0.2); + + label->set_point(q_lab, p_lab); + label->angle(0.0); + + labels.add(label); + } + + double x_lab = factor->mark(layers_number); + double x_a = x_lab, y_a = 0.0; + user_mtx.transform(&x_a, &y_a); + double q_a = x_a; + mark.move_to(q_a, p_lab); + mark.line_to(q_a, p_lab + y_spacing); + + p_lab += y_spacing; + } + + this->draw_grid(x_axis, u, user_mtx, ln); + + return y_spacing * layers_number; +} + +static inline double approx_text_height(double text_size) +{ + return text_size * 1.5; +} + +plot_layout plot::compute_plot_layout(const agg::trans_affine& canvas_mtx, bool do_legends) +{ + plot_layout layout; + + const double sx = canvas_mtx.sx, sy = canvas_mtx.sy; + const double ppad = double(canvas_margin_prop_space) / 1000.0; + const double fpad = double(canvas_margin_fixed_space); + const double size_frac_x = 0.125, size_frac_y = 0.05; + + double dxl, dxr, dyb, dyt; + + dxl = dxr = fpad + ppad * sx; + dyb = dyt = fpad + ppad * sy; + + if (!str_is_null(&m_title)) + { + const double scale = compute_scale(canvas_mtx); + const double ptpad = double(axis_title_prop_space) / 1000.0; + const double title_text_size = get_default_font_size(text_plot_title, scale); + const double th = approx_text_height(title_text_size); + + double x = 0.5, y = 1.0; + canvas_mtx.transform(&x, &y); + y -= ptpad + dyt + title_text_size; + + layout.title_pos = plot_layout::point(x, y); + layout.title_font_size = title_text_size; + + dyt += 2 * ptpad + th; + } + + for (int k = 0; k < 4 && do_legends; k++) + { + plot* mp = m_legend[k]; + + if (mp) + { + agg::rect_base<double> bb; + mp->get_bounding_rect(bb); + + double bb_dx = bb.x2 - bb.x1, bb_dy = bb.y2 - bb.y1; + double dx, dy; + double px, py; + switch (k) + { + case right: + dx = max(sx * size_frac_x, bb_dx); + dy = dx * bb_dy / bb_dx; + px = sx - dx - ppad * sx - dxr; + py = (sy - dy) / 2; + dxr += dx + 2 * ppad * sx; + break; + case left: + dx = max(sx * size_frac_x, bb_dx); + dy = dx * bb_dy / bb_dx; + px = ppad * sx + dxr; + py = (sy - dy) / 2; + dxl += dx + 2 * ppad * sx; + break; + case bottom: + dy = sy * size_frac_y; + dx = dy * bb_dx / bb_dy; + py = ppad * sy + dyb; + px = (sx - dx) / 2; + dyb += dy + 2 * ppad * sy; + break; + case top: + dy = sy * size_frac_y; + dx = dy * bb_dx / bb_dy; + py = sy - dy - ppad * sy - dyt; + px = (sx - dx) / 2; + dyt += dy + 2 * ppad * sy; + break; + default: + /* */ + ; + } + + if (px >= 0 && py >= 0 && px + dx < sx && py + dy < sy) + { + const double x0 = canvas_mtx.tx + px, y0 = canvas_mtx.ty + py; + layout.legend_area[k] = agg::trans_affine(dx, 0.0, 0.0, dy, x0, y0); + } + else + { + plot_layout::set_area_undefined(layout.legend_area[k]); + } + } + } + + double x0 = canvas_mtx.tx + dxl, y0 = canvas_mtx.ty + dyb; + double ssx = sx - (dxl + dxr), ssy = sy - (dyb + dyt); + layout.plot_area = agg::trans_affine(ssx, 0.0, 0.0, ssy, x0, y0); + + return layout; +} + +void plot::draw_legends(canvas_type& canvas, const plot_layout& layout) +{ + if (!str_is_null(&m_title)) + { + const plot_layout::point& pos = layout.title_pos; + draw::text title(m_title.cstr(), layout.title_font_size, 0.5, 0.0); + title.set_point(pos.x, pos.y); + title.apply_transform(identity_matrix, 1.0); + canvas.draw(title, colors::black); + } + + for (int k = 0; k < 4; k++) + { + plot* mp = m_legend[k]; + const agg::trans_affine& mtx = layout.legend_area[k]; + + if (mp && plot_layout::is_area_defined(mtx)) + { + agg::rect_i clip = rect_of_slot_matrix<int>(mtx); + plot_layout mp_layout = mp->compute_plot_layout(mtx, false); + mp->draw_simple(canvas, mp_layout, &clip); + } + } +} + +// Draw the axis elements and labels and set layout.plot_active_area +// to the actual plotting are matrix. +void plot::draw_axis(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) +{ + if (!m_use_units) + { + layout.plot_active_area = layout.plot_area; + return; + } + + double scale = compute_scale(layout.plot_area); + + if (clip) + canvas.clip_box(*clip); + + const agg::trans_affine& m = layout.plot_active_area; + + agg::path_storage box; + sg_object_gen<agg::conv_transform<agg::path_storage> > boxtr(box, m); + trans::stroke_a boxvs(&boxtr); + + box.move_to(0.0, 0.0); + box.line_to(0.0, 1.0); + box.line_to(1.0, 1.0); + box.line_to(1.0, 0.0); + box.close_polygon(); + + agg::path_storage mark; + sg_object_gen<agg::conv_transform<agg::path_storage> > mark_tr(mark, m); + trans::stroke_a mark_stroke(&mark_tr); + + agg::path_storage ln; + sg_object_gen<agg::conv_transform<agg::path_storage> > ln_tr(ln, m); + trans::dash_a lndash(&ln_tr); + trans::stroke_a lns(&lndash); + + const double label_text_size = get_default_font_size(text_axis_title, scale); + const double plpad = double(axis_label_prop_space) / 1000.0; + const double ptpad = double(axis_title_prop_space) / 1000.0; + + ptr_list<draw::text> labels; + + double dy_label = 0, pdy_label = 0; + if (this->m_xaxis_hol) + pdy_label = draw_xaxis_factors(m_ux, m_trans, labels, this->m_xaxis_hol, scale, mark, ln); + else + dy_label = draw_axis_m(x_axis, m_ux, m_trans, labels, scale, mark, ln); + + double dx_label = draw_axis_m(y_axis, m_uy, m_trans, labels, scale, mark, ln); + + double ppad_left = plpad, ppad_right = plpad; + double ppad_bottom = plpad + pdy_label, ppad_top = plpad; + double dx_left = dx_label, dx_right = 0.0; + double dy_bottom = dy_label, dy_top = 0.0; + + if (!str_is_null(&m_y_axis.title)) + { + dx_left += approx_text_height(label_text_size); + ppad_left += ptpad; + } + + if (!str_is_null(&m_x_axis.title)) + { + dy_bottom += approx_text_height(label_text_size); + ppad_bottom += ptpad; + } + + const double sx = layout.plot_area.sx, sy = layout.plot_area.sy; + const double x0 = layout.plot_area.tx, y0 = layout.plot_area.ty; + + const double xppad = (ppad_left + ppad_right); + const double lsx = (dx_left + dx_right + xppad * sx) / (1 + xppad); + + const double yppad = (ppad_bottom + ppad_top); + const double lsy = (dy_bottom + dy_top + yppad * sy) / (1 + yppad); + + const double sxr = sx - lsx; + const double syr = sy - lsy; + + const double aax = x0 + dx_left + ppad_left * sxr; + const double aay = y0 + dy_bottom + ppad_bottom * syr; + layout.set_plot_active_area(sxr, syr, aax, aay); + + for (unsigned j = 0; j < labels.size(); j++) + { + draw::text* label = labels[j]; + label->apply_transform(m, 1.0); + canvas.draw(*label, colors::black); + } + + lndash.add_dash(7.0, 3.0); + + lns.width(std_line_width(scale, 0.15)); + canvas.draw(lns, colors::black); + + mark_stroke.width(std_line_width(scale, 0.75)); + canvas.draw(mark_stroke, colors::black); + + boxvs.width(std_line_width(scale, 0.75)); + canvas.draw(boxvs, colors::black); + + if (!str_is_null(&m_x_axis.title)) + { + double labx = m.sx * 0.5 + m.tx; + double laby = y0; + + const char* text = m_x_axis.title.cstr(); + draw::text xlabel(text, label_text_size, 0.5, 0.0); + xlabel.set_point(labx, laby); + xlabel.apply_transform(identity_matrix, 1.0); + + canvas.draw(xlabel, colors::black); + } + + if (!str_is_null(&m_y_axis.title)) + { + double labx = x0; + double laby = m.sy * 0.5 + m.ty; + + const char* text = m_y_axis.title.cstr(); + draw::text ylabel(text, label_text_size, 0.5, 1.0); + ylabel.set_point(labx, laby); + ylabel.angle(M_PI/2.0); + ylabel.apply_transform(identity_matrix, 1.0); + + canvas.draw(ylabel, colors::black); + } + + if (clip) + canvas.reset_clipping(); +} + +void plot::set_axis_labels_angle(axis_e axis_dir, double angle) +{ + get_axis(axis_dir).set_labels_angle(angle); + m_need_redraw = true; + compute_user_trans(); +} + +void plot::set_units(bool use_units) +{ + if (m_use_units != use_units) + { + m_use_units = use_units; + m_need_redraw = true; + compute_user_trans(); + } +} + +void plot::update_units() +{ + if (m_rect.is_defined()) + { + const rect_base<double>& r = m_rect.rect(); + m_ux = units(r.x1, r.x2); + m_uy = units(r.y1, r.y2); + } + else + { + m_ux = units(); + m_uy = units(); + } + + compute_user_trans(); +} + +void plot::set_limits(const agg::rect_base<double>& r) +{ + m_rect.set(r); + update_units(); + m_need_redraw = true; +} + +void plot::unset_limits() +{ + m_rect.clear(); + update_units(); + m_need_redraw = true; +} + +void plot::layer_dispose_elements(plot::item_list* layer) +{ + unsigned n = layer->size(); + for (unsigned k = 0; k < n; k++) + { + RM::dispose(layer->at(k).vs); + } +} + +bool plot::push_layer() +{ + if (m_layers.size() >= max_layers) + return false; + + item_list *new_layer = new(std::nothrow) item_list(); + if (new_layer) + { + before_draw(); + push_drawing_queue(); + m_layers.add(new_layer); + return true; + } + + return false; +} + +bool plot::pop_layer() +{ + if (m_layers.size() <= 1) + return false; + + unsigned n = m_layers.size(); + item_list* layer = m_layers[n-1]; + m_layers.inc_size(-1); + layer_dispose_elements(layer); + delete layer; + + clear_drawing_queue(); + m_need_redraw = true; + + return true; +} + +void plot::clear_current_layer() +{ + item_list* current = current_layer(); + clear_drawing_queue(); + layer_dispose_elements(current); + current->clear(); + m_changes_pending = m_changes_accu; + m_changes_accu.clear(); +} + +int plot::current_layer_index() +{ + return m_layers.size(); +} diff --git a/agg-plot/plot.h b/agg-plot/plot.h index 06d0d35a..25b0ce72 100644 --- a/agg-plot/plot.h +++ b/agg-plot/plot.h @@ -36,6 +36,7 @@ #include "text.h" #include "categories.h" #include "sg_object.h" +#include "factor_labels.h" #include "agg_array.h" #include "agg_bounding_rect.h" @@ -123,7 +124,8 @@ struct plot_item { }; }; -template<class ResourceManager> +typedef manage_owner RM; + class plot { static const unsigned max_layers = 8; @@ -239,7 +241,8 @@ public: m_drawing_queue(0), m_clip_flag(true), m_need_redraw(true), m_rect(), m_use_units(use_units), m_pad_units(false), m_title(), - m_sync_mode(true), m_x_axis(x_axis), m_y_axis(y_axis) + m_sync_mode(true), m_x_axis(x_axis), m_y_axis(y_axis), + m_xaxis_hol(0) { m_layers.add(&m_root_layer); compute_user_trans(); @@ -256,6 +259,8 @@ public: if (k > 0) delete layer; } + + delete m_xaxis_hol; }; str& title() { @@ -301,6 +306,14 @@ public: void set_limits(const agg::rect_base<double>& r); void unset_limits(); + ptr_list<factor_labels>* get_xaxis_hol() { return m_xaxis_hol; } + + void set_xaxis_hol(ptr_list<factor_labels>* hol) + { + delete m_xaxis_hol; + m_xaxis_hol = hol; + } + virtual void add(sg_object* vs, agg::rgba8& color, bool outline); virtual void before_draw() { } @@ -417,10 +430,19 @@ protected: void draw_virtual_canvas(canvas_type& canvas, plot_layout& layout, const agg::rect_i* r); void draw_simple(canvas_type& canvas, plot_layout& layout, const agg::rect_i* r); + void draw_grid(const axis_e dir, const units& u, + const agg::trans_affine& user_mtx, + agg::path_storage& ln); + double draw_axis_m(axis_e dir, units& u, const agg::trans_affine& user_mtx, ptr_list<draw::text>& labels, double scale, agg::path_storage& mark, agg::path_storage& ln); + double draw_xaxis_factors(units& u, const agg::trans_affine& user_mtx, + ptr_list<draw::text>& labels, + ptr_list<factor_labels>* f_labels, double scale, + agg::path_storage& mark, agg::path_storage& ln); + void draw_elements(canvas_type &canvas, const plot_layout& layout); void draw_element(item& c, canvas_type &canvas, const agg::trans_affine& m); void draw_axis(canvas_type& can, plot_layout& layout, const agg::rect_i* clip = 0); @@ -486,144 +508,12 @@ private: axis m_x_axis, m_y_axis; plot* m_legend[4]; -}; - -static double compute_scale(const agg::trans_affine& m) -{ - return m.scale() / 480.0; -} - -static double -std_line_width(double scale, double w = 1.0) -{ -#if 0 - const double dsf = M_LN10; - double ls = log(scale) / dsf; - return exp(round(ls) * dsf) * w * 1.5; -#else - return w * 1.5; -#endif -} - -template <class RM> -void plot<RM>::commit_pending_draw() -{ - push_drawing_queue(); - m_need_redraw = false; - m_changes_pending.clear(); -} - -template <class RM> -void plot<RM>::add(sg_object* vs, agg::rgba8& color, bool outline) -{ - item d(vs, color, outline); - list<item> *new_node = new list<item>(d); - m_drawing_queue = list<item>::push_back(m_drawing_queue, new_node); - RM::acquire(vs); -} - -template <class RM> -void plot<RM>::push_drawing_queue() -{ - item_list* layer = current_layer(); - for (list<item> *c = m_drawing_queue; c != 0; c = c->next()) - { - layer->add(c->content()); - } - - while (m_drawing_queue) - m_drawing_queue = list<item>::pop(m_drawing_queue); -} - -template <class RM> -void plot<RM>::clear_drawing_queue() -{ - while (m_drawing_queue) - { - item& d = m_drawing_queue->content(); - RM::dispose(d.vs); - m_drawing_queue = list<item>::pop(m_drawing_queue); - } -} - -static bool area_is_valid(const agg::trans_affine& b) -{ - const double thresold = 40.0; - return (b.sx > thresold && b.sy > thresold); -} -template <class RM> -void plot<RM>::draw_virtual_canvas(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) -{ - before_draw(); - draw_legends(canvas, layout); - - if (area_is_valid(layout.plot_area)) - { - draw_axis(canvas, layout, clip); - draw_elements(canvas, layout); - } -}; - -template <class RM> -void plot<RM>::draw_simple(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) -{ - before_draw(); - draw_axis(canvas, layout, clip); - draw_elements(canvas, layout); + ptr_list<factor_labels>* m_xaxis_hol; }; -template <class RM> -void plot<RM>::draw_element(item& c, canvas_type& canvas, const agg::trans_affine& m) -{ - sg_object& vs = c.content(); - vs.apply_transform(m, 1.0); - - if (c.outline) - canvas.draw_outline(vs, c.color); - else - canvas.draw(vs, c.color); -} - -template <class RM> -agg::trans_affine plot<RM>::get_model_matrix(const plot_layout& layout) -{ - agg::trans_affine m = m_trans; - trans_affine_compose (m, layout.plot_active_area); - return m; -} - -template<class RM> -void plot<RM>::clip_plot_area(canvas_type& canvas, const agg::trans_affine& area_mtx) -{ - if (this->clip_is_active()) - { - agg::rect_base<int> clip = rect_of_slot_matrix<int>(area_mtx); - canvas.clip_box(clip); - } -} - -template <class RM> -void plot<RM>::draw_elements(canvas_type& canvas, const plot_layout& layout) -{ - const agg::trans_affine m = get_model_matrix(layout); - - this->clip_plot_area(canvas, layout.plot_active_area); - - for (unsigned k = 0; k < m_layers.size(); k++) - { - item_list& layer = *(m_layers[k]); - for (unsigned j = 0; j < layer.size(); j++) - { - draw_element(layer[j], canvas, m); - } - } - - canvas.reset_clipping(); -} - -template <class RM> -template <class Canvas> void plot<RM>::draw_queue(Canvas& _canvas, const agg::trans_affine& canvas_mtx, const plot_render_info& inf, opt_rect<double>& bb) +template <class Canvas> +void plot::draw_queue(Canvas& _canvas, const agg::trans_affine& canvas_mtx, const plot_render_info& inf, opt_rect<double>& bb) { canvas_adapter<Canvas> canvas(&_canvas); before_draw(); @@ -633,7 +523,7 @@ template <class Canvas> void plot<RM>::draw_queue(Canvas& _canvas, const agg::tr this->clip_plot_area(canvas, layout.plot_active_area); - typedef typename plot<RM>::iterator iter_type; + typedef typename plot::iterator iter_type; iter_type *c0 = m_drawing_queue; for (iter_type *c = c0; c != 0; c = c->next()) { @@ -658,483 +548,4 @@ template <class Canvas> void plot<RM>::draw_queue(Canvas& _canvas, const agg::tr canvas.reset_clipping(); } -template <class RM> -void plot<RM>::compute_user_trans() -{ - agg::rect_base<double> r; - - if (m_use_units && m_pad_units) - { - int ixi, ixs, iyi, iys; - double xd, yd; - m_ux.limits(ixi, ixs, xd); - r.x1 = ixi * xd; - r.x2 = ixs * xd; - - m_uy.limits(iyi, iys, yd); - r.y1 = iyi * yd; - r.y2 = iys * yd; - } - else - { - r = m_rect.is_defined() ? m_rect.rect() : agg::rect_base<double>(0.0, 0.0, 1.0, 1.0); - } - - double dx = r.x2 - r.x1, dy = r.y2 - r.y1; - double fx = (dx == 0 ? 1.0 : 1/dx), fy = (dy == 0 ? 1.0 : 1/dy); - this->m_trans = agg::trans_affine(fx, 0.0, 0.0, fy, -r.x1 * fx, -r.y1 * fy); -} - -template <class RM> -double plot<RM>::draw_axis_m(axis_e dir, units& u, - const agg::trans_affine& user_mtx, - ptr_list<draw::text>& labels, double scale, - agg::path_storage& mark, agg::path_storage& ln) -{ - const double ppad = double(axis_label_prop_space) / 1000.0; - const double text_label_size = get_default_font_size(text_axis_labels, scale); - const double eps = 1.0e-3; - - opt_rect<double> bb; - agg::rect_base<double> r; - - bool isx = (dir == x_axis); - - const axis& ax = get_axis(dir); - double hj = ax.labels_hjustif(), vj = ax.labels_vjustif(); - double langle = ax.labels_angle(); - - category_map::iterator clabels(ax.categories); - units_iterator ulabels(u, ax.format_tag, ax.label_format()); - - label_iterator* ilabels = (ax.use_categories ? (label_iterator*) &clabels : (label_iterator*) &ulabels); - - double uq; - const char* text; - while (ilabels->next(uq, text)) - { - double x = (isx ? uq : 0.0), y = (isx ? 0.0 : uq); - user_mtx.transform(&x, &y); - - double q = (isx ? x : y); - - if (q < -eps || q > 1.0 + eps) - continue; - - draw::text* label = new draw::text(text, text_label_size, hj, vj); - - label->set_point(isx ? q : -ppad, isx ? -ppad : q); - label->angle(langle); - - agg::bounding_rect_single(*label, 0, &r.x1, &r.y1, &r.x2, &r.y2); - bb.add<rect_union>(r); - - labels.add(label); - - mark.move_to(isx ? q : 0.0 , isx ? 0.0 : q); - mark.line_to(isx ? q : -0.01, isx ? -0.01 : q); - } - - int jinf = u.begin(), jsup = u.end(); - for (int j = jinf+1; j < jsup; j++) - { - double uq = u.mark_value(j); - double x = (isx ? uq : 0), y = (isx ? 0.0 : uq); - user_mtx.transform(&x, &y); - double q = (isx ? x : y); - - if (q >= -eps && q <= 1.0 + eps) - { - ln.move_to(isx ? q : 0.0, isx ? 0.0 : q); - ln.line_to(isx ? q : 1.0, isx ? 1.0 : q); - } - } - - double label_size; - if (bb.is_defined()) - { - const agg::rect_base<double>& br = bb.rect(); - label_size = (isx ? br.y2 - br.y1 : br.x2 - br.x1); - } - else - { - label_size = 0.0; - } - - return label_size; -} - -static inline double approx_text_height(double text_size) -{ - return text_size * 1.5; -} - -template <class RM> -plot_layout plot<RM>::compute_plot_layout(const agg::trans_affine& canvas_mtx, bool do_legends) -{ - plot_layout layout; - - const double sx = canvas_mtx.sx, sy = canvas_mtx.sy; - const double ppad = double(canvas_margin_prop_space) / 1000.0; - const double fpad = double(canvas_margin_fixed_space); - const double size_frac_x = 0.125, size_frac_y = 0.05; - - double dxl, dxr, dyb, dyt; - - dxl = dxr = fpad + ppad * sx; - dyb = dyt = fpad + ppad * sy; - - if (!str_is_null(&m_title)) - { - const double scale = compute_scale(canvas_mtx); - const double ptpad = double(axis_title_prop_space) / 1000.0; - const double title_text_size = get_default_font_size(text_plot_title, scale); - const double th = approx_text_height(title_text_size); - - double x = 0.5, y = 1.0; - canvas_mtx.transform(&x, &y); - y -= ptpad + dyt + title_text_size; - - layout.title_pos = plot_layout::point(x, y); - layout.title_font_size = title_text_size; - - dyt += 2 * ptpad + th; - } - - for (int k = 0; k < 4 && do_legends; k++) - { - plot* mp = m_legend[k]; - - if (mp) - { - agg::rect_base<double> bb; - mp->get_bounding_rect(bb); - - double bb_dx = bb.x2 - bb.x1, bb_dy = bb.y2 - bb.y1; - double dx, dy; - double px, py; - switch (k) - { - case right: - dx = max(sx * size_frac_x, bb_dx); - dy = dx * bb_dy / bb_dx; - px = sx - dx - ppad * sx - dxr; - py = (sy - dy) / 2; - dxr += dx + 2 * ppad * sx; - break; - case left: - dx = max(sx * size_frac_x, bb_dx); - dy = dx * bb_dy / bb_dx; - px = ppad * sx + dxr; - py = (sy - dy) / 2; - dxl += dx + 2 * ppad * sx; - break; - case bottom: - dy = sy * size_frac_y; - dx = dy * bb_dx / bb_dy; - py = ppad * sy + dyb; - px = (sx - dx) / 2; - dyb += dy + 2 * ppad * sy; - break; - case top: - dy = sy * size_frac_y; - dx = dy * bb_dx / bb_dy; - py = sy - dy - ppad * sy - dyt; - px = (sx - dx) / 2; - dyt += dy + 2 * ppad * sy; - break; - default: - /* */ - ; - } - - if (px >= 0 && py >= 0 && px + dx < sx && py + dy < sy) - { - const double x0 = canvas_mtx.tx + px, y0 = canvas_mtx.ty + py; - layout.legend_area[k] = agg::trans_affine(dx, 0.0, 0.0, dy, x0, y0); - } - else - { - plot_layout::set_area_undefined(layout.legend_area[k]); - } - } - } - - double x0 = canvas_mtx.tx + dxl, y0 = canvas_mtx.ty + dyb; - double ssx = sx - (dxl + dxr), ssy = sy - (dyb + dyt); - layout.plot_area = agg::trans_affine(ssx, 0.0, 0.0, ssy, x0, y0); - - return layout; -} - -template <class RM> -void plot<RM>::draw_legends(canvas_type& canvas, const plot_layout& layout) -{ - if (!str_is_null(&m_title)) - { - const plot_layout::point& pos = layout.title_pos; - draw::text title(m_title.cstr(), layout.title_font_size, 0.5, 0.0); - title.set_point(pos.x, pos.y); - title.apply_transform(identity_matrix, 1.0); - canvas.draw(title, colors::black); - } - - for (int k = 0; k < 4; k++) - { - plot* mp = m_legend[k]; - const agg::trans_affine& mtx = layout.legend_area[k]; - - if (mp && plot_layout::is_area_defined(mtx)) - { - agg::rect_i clip = rect_of_slot_matrix<int>(mtx); - plot_layout mp_layout = mp->compute_plot_layout(mtx, false); - mp->draw_simple(canvas, mp_layout, &clip); - } - } -} - -// Draw the axis elements and labels and set layout.plot_active_area -// to the actual plotting are matrix. -template <class RM> -void plot<RM>::draw_axis(canvas_type& canvas, plot_layout& layout, const agg::rect_i* clip) -{ - if (!m_use_units) - { - layout.plot_active_area = layout.plot_area; - return; - } - - double scale = compute_scale(layout.plot_area); - - if (clip) - canvas.clip_box(*clip); - - const agg::trans_affine& m = layout.plot_active_area; - - agg::path_storage box; - sg_object_gen<agg::conv_transform<agg::path_storage> > boxtr(box, m); - trans::stroke_a boxvs(&boxtr); - - box.move_to(0.0, 0.0); - box.line_to(0.0, 1.0); - box.line_to(1.0, 1.0); - box.line_to(1.0, 0.0); - box.close_polygon(); - - agg::path_storage mark; - sg_object_gen<agg::conv_transform<agg::path_storage> > mark_tr(mark, m); - trans::stroke_a mark_stroke(&mark_tr); - - agg::path_storage ln; - sg_object_gen<agg::conv_transform<agg::path_storage> > ln_tr(ln, m); - trans::dash_a lndash(&ln_tr); - trans::stroke_a lns(&lndash); - - const double label_text_size = get_default_font_size(text_axis_title, scale); - const double plpad = double(axis_label_prop_space) / 1000.0; - const double ptpad = double(axis_title_prop_space) / 1000.0; - - ptr_list<draw::text> labels; - - double dy_label = draw_axis_m(x_axis, m_ux, m_trans, labels, scale, mark, ln); - double dx_label = draw_axis_m(y_axis, m_uy, m_trans, labels, scale, mark, ln); - - double ppad_left = plpad, ppad_right = plpad; - double ppad_bottom = plpad, ppad_top = plpad; - double dx_left = dx_label, dx_right = 0.0; - double dy_bottom = dy_label, dy_top = 0.0; - - if (!str_is_null(&m_y_axis.title)) - { - dx_left += approx_text_height(label_text_size); - ppad_left += ptpad; - } - - if (!str_is_null(&m_x_axis.title)) - { - dy_bottom += approx_text_height(label_text_size); - ppad_bottom += ptpad; - } - - const double sx = layout.plot_area.sx, sy = layout.plot_area.sy; - const double x0 = layout.plot_area.tx, y0 = layout.plot_area.ty; - - const double xppad = (ppad_left + ppad_right); - const double lsx = (dx_left + dx_right + xppad * sx) / (1 + xppad); - - const double yppad = (ppad_bottom + ppad_top); - const double lsy = (dy_bottom + dy_top + yppad * sy) / (1 + yppad); - - const double sxr = sx - lsx; - const double syr = sy - lsy; - - const double aax = x0 + dx_left + ppad_left * sxr; - const double aay = y0 + dy_bottom + ppad_bottom * syr; - layout.set_plot_active_area(sxr, syr, aax, aay); - - for (unsigned j = 0; j < labels.size(); j++) - { - draw::text* label = labels[j]; - label->apply_transform(m, 1.0); - canvas.draw(*label, colors::black); - } - - lndash.add_dash(7.0, 3.0); - - lns.width(std_line_width(scale, 0.15)); - canvas.draw(lns, colors::black); - - mark_stroke.width(std_line_width(scale, 0.75)); - canvas.draw(mark_stroke, colors::black); - - boxvs.width(std_line_width(scale, 0.75)); - canvas.draw(boxvs, colors::black); - - if (!str_is_null(&m_x_axis.title)) - { - double labx = m.sx * 0.5 + m.tx; - double laby = y0; - - const char* text = m_x_axis.title.cstr(); - draw::text xlabel(text, label_text_size, 0.5, 0.0); - xlabel.set_point(labx, laby); - xlabel.apply_transform(identity_matrix, 1.0); - - canvas.draw(xlabel, colors::black); - } - - if (!str_is_null(&m_y_axis.title)) - { - double labx = x0; - double laby = m.sy * 0.5 + m.ty; - - const char* text = m_y_axis.title.cstr(); - draw::text ylabel(text, label_text_size, 0.5, 1.0); - ylabel.set_point(labx, laby); - ylabel.angle(M_PI/2.0); - ylabel.apply_transform(identity_matrix, 1.0); - - canvas.draw(ylabel, colors::black); - } - - if (clip) - canvas.reset_clipping(); -} - -template<class RM> -void plot<RM>::set_axis_labels_angle(axis_e axis_dir, double angle) -{ - get_axis(axis_dir).set_labels_angle(angle); - m_need_redraw = true; - compute_user_trans(); -} - -template<class RM> -void plot<RM>::set_units(bool use_units) -{ - if (m_use_units != use_units) - { - m_use_units = use_units; - m_need_redraw = true; - compute_user_trans(); - } -} - -template<class RM> -void plot<RM>::update_units() -{ - if (m_rect.is_defined()) - { - const rect_base<double>& r = m_rect.rect(); - m_ux = units(r.x1, r.x2); - m_uy = units(r.y1, r.y2); - } - else - { - m_ux = units(); - m_uy = units(); - } - - compute_user_trans(); -} - -template<class RM> -void plot<RM>::set_limits(const agg::rect_base<double>& r) -{ - m_rect.set(r); - update_units(); - m_need_redraw = true; -} - -template<class RM> -void plot<RM>::unset_limits() -{ - m_rect.clear(); - update_units(); - m_need_redraw = true; -} - -template<class RM> -void plot<RM>::layer_dispose_elements(plot<RM>::item_list* layer) -{ - unsigned n = layer->size(); - for (unsigned k = 0; k < n; k++) - { - RM::dispose(layer->at(k).vs); - } -} - -template<class RM> -bool plot<RM>::push_layer() -{ - if (m_layers.size() >= max_layers) - return false; - - item_list *new_layer = new(std::nothrow) item_list(); - if (new_layer) - { - before_draw(); - push_drawing_queue(); - m_layers.add(new_layer); - return true; - } - - return false; -} - -template<class RM> -bool plot<RM>::pop_layer() -{ - if (m_layers.size() <= 1) - return false; - - unsigned n = m_layers.size(); - item_list* layer = m_layers[n-1]; - m_layers.inc_size(-1); - layer_dispose_elements(layer); - delete layer; - - clear_drawing_queue(); - m_need_redraw = true; - - return true; -} - -template <class RM> -void plot<RM>::clear_current_layer() -{ - item_list* current = current_layer(); - clear_drawing_queue(); - layer_dispose_elements(current); - current->clear(); - m_changes_pending = m_changes_accu; - m_changes_accu.clear(); -} - -template <class RM> -int plot<RM>::current_layer_index() -{ - return m_layers.size(); -} - #endif diff --git a/agg-plot/units.h b/agg-plot/units.h index f315d804..b929e38d 100644 --- a/agg-plot/units.h +++ b/agg-plot/units.h @@ -90,7 +90,6 @@ public: val = m_units.mark_value(m_index); text = m_buffer; - text = m_buffer; m_index ++; return true; } diff --git a/agg-plot/utils.h b/agg-plot/utils.h index d1274d32..1e66be31 100644 --- a/agg-plot/utils.h +++ b/agg-plot/utils.h @@ -40,6 +40,10 @@ public: return m_list[k]; } + T* at(unsigned k) const { + return m_list[k]; + } + unsigned size() const { return m_list.size(); } diff --git a/fox-gui/lua_plot_window.cpp b/fox-gui/lua_plot_window.cpp index 15a3107e..f327aef7 100644 --- a/fox-gui/lua_plot_window.cpp +++ b/fox-gui/lua_plot_window.cpp @@ -40,7 +40,7 @@ static const struct luaL_Reg fox_window_methods[] = __END_DECLS -typedef plot<manage_owner> sg_plot; +typedef plot sg_plot; class window_mutex { public: @@ -20,6 +20,7 @@ local cat = table.concat local fmt = string.format +local tostring = tostring do local ffi = require('ffi') @@ -61,6 +62,13 @@ end local max_depth = 3 +local function cdata_tos(t, deep) + local tp = gsl_type and gsl_type(t) or 'cdata' + if tp ~= 'cdata' and t.show then + return (deep and t:show() or fmt("<%s: %p>", tp, t)) + end +end + tos = function (t, depth) local tp = type(t) if tp == 'table' then @@ -92,9 +100,9 @@ tos = function (t, depth) end end elseif tp == 'cdata' then - local tpext = gsl_type and gsl_type(t) or tp - if tpext ~= 'cdata' and t.show then - return (depth == 0 and t:show() or fmt("<%s: %p>", tpext, t)) + local ok, s = pcall(cdata_tos, t, depth == 0) + if ok and type(s) == 'string' then + return s end end return tostring(t) diff --git a/matrix.lua b/matrix.lua index 87df4581..d7c5e75b 100644 --- a/matrix.lua +++ b/matrix.lua @@ -3,7 +3,7 @@ local ffi = require 'ffi' local gsl = require 'gsl' -local sqrt, abs = math.sqrt, math.abs +local sqrt, abs, floor = math.sqrt, math.abs, math.floor local format = string.format local check = require 'check' @@ -208,21 +208,34 @@ local function itostr(im, eps, fmt, signed) end end +local function is_small_integer(x) + local ax = abs(x) + return (ax < 2^31 and floor(ax) == ax) +end + local function recttostr(x, y, eps) local x_sub, y_sub = abs(x) < eps, abs(y) < eps - local fmt = '%.8g' + local fmt_x, fmt_y = '%.8g', '%.8g' + if is_small_integer(x) then + fmt_x = '%.0f' + x_sub = false + end + if is_small_integer(y) then + fmt_y = '%.0f' + y_sub = false + end if not x_sub then local sign = x+eps < 0 and '-' or '' local ax = abs(x) if y_sub then - return format('%s'..fmt, sign, ax) + return format('%s'..fmt_x, sign, ax) else - return format('%s'..fmt..'%s', sign, ax, itostr(y, eps, fmt, true)) + return format('%s'..fmt_x..'%s', sign, ax, itostr(y, eps, fmt_y, true)) end else - return (y_sub and '0' or itostr(y, eps, fmt, false)) + return (y_sub and '0' or itostr(y, eps, fmt_y, false)) end end diff --git a/scripts/dos2unix.py b/scripts/dos2unix.py new file mode 100755 index 00000000..5c2e6266 --- /dev/null +++ b/scripts/dos2unix.py @@ -0,0 +1,34 @@ +#!/usr/bin/python +import os +import re +import sys + +def dos2unix(filename): + tmp_filename = filename + '.tmp' + + try: + fsrc = open(filename, "rb") + fdst = open(tmp_filename, "wb") + for ln in fsrc: + lnu = re.sub(r'015円\n', '\n', ln) + fdst.write(lnu) + fsrc.close() + fdst.close() + except OSError as err: + print 'Error', err.strerror + else: + try: + os.unlink(filename) + os.rename(tmp_filename, filename) + except OSError as err: + print 'Error', err.strerror + +for filename in sys.argv[1:]: + inf = os.popen("file " + filename, "r") + for ln in inf: + if re.search(r'with CRLF line terminators', ln): + dos2unix(filename) + break + else: + print "File ", filename, "not in DOS format" + diff --git a/scripts/enum2lua.py b/scripts/enum2lua.py new file mode 100644 index 00000000..0e574ae7 --- /dev/null +++ b/scripts/enum2lua.py @@ -0,0 +1,12 @@ +import re +import sys + +f = open(sys.argv[1], 'r') +count = 0 +for line in f: + m = re.match(r'\s*SEL_([A-Z_]+),(.*)', line) + if m: + print('SEL.%s = %i' % (m.group(1), count) + m.group(2)) + count += 1 +f.close() + |