Remove template parameter from plot class - gsl-shell.git - gsl-shell

index : gsl-shell.git
gsl-shell
summary refs log tree commit diff
path: root/agg-plot/plot.cpp
diff options
context:
space:
mode:
authorFrancesco Abbate <francesco.bbt@gmail.com>2013年02月03日 23:45:28 +0100
committerFrancesco Abbate <francesco.bbt@gmail.com>2013年02月03日 23:45:28 +0100
commit474642a4e98d378a5ab3cdb124c182135f5a5493 (patch)
treea02d7ac0d7cdf45695ccb5bbbe87bdbb1c809fa0 /agg-plot/plot.cpp
parente88806a5a5760aba7f5e2cd633ac3c3de2c22682 (diff)
downloadgsl-shell-474642a4e98d378a5ab3cdb124c182135f5a5493.tar.gz
Remove template parameter from plot class
Diffstat (limited to 'agg-plot/plot.cpp')
-rw-r--r--agg-plot/plot.cpp 660
1 files changed, 660 insertions, 0 deletions
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();
+}
generated by cgit v1.2.3 (git 2.39.1) at 2025年09月16日 12:41:43 +0000

AltStyle によって変換されたページ (->オリジナル) /