Add support for plot legends - gsl-shell.git - gsl-shell

index : gsl-shell.git
gsl-shell
summary refs log tree commit diff
path: root/agg-plot
diff options
context:
space:
mode:
authorFrancesco Abbate <francesco.bbt@gmail.com>2012年01月11日 16:41:22 +0100
committerFrancesco Abbate <francesco.bbt@gmail.com>2012年01月30日 21:26:02 +0100
commit3835be08da347dcaf854d61dc21f0cb52164ef8a (patch)
treec2a6772c5dc17fbfb551fbdb36e4d4617a82dd31 /agg-plot
parent900c2a906c1a7ec8043b3f6eb9e74ec1c8f05063 (diff)
downloadgsl-shell-3835be08da347dcaf854d61dc21f0cb52164ef8a.tar.gz
Add support for plot legends
Introduce also the textshape graphical object required to create legends effectively.
Diffstat (limited to 'agg-plot')
-rw-r--r--agg-plot/lua-draw.cpp 31
-rw-r--r--agg-plot/lua-plot.cpp 34
-rw-r--r--agg-plot/plot-auto.h 6
-rw-r--r--agg-plot/plot.h 97
-rw-r--r--agg-plot/rect.h 3
-rw-r--r--agg-plot/text-shape.h 100
-rw-r--r--agg-plot/text.cpp 3
-rw-r--r--agg-plot/utils.h 6
8 files changed, 269 insertions, 11 deletions
diff --git a/agg-plot/lua-draw.cpp b/agg-plot/lua-draw.cpp
index 932d9c26..b9a3a13e 100644
--- a/agg-plot/lua-draw.cpp
+++ b/agg-plot/lua-draw.cpp
@@ -26,6 +26,7 @@ extern "C" {
}
#include "lua-draw.h"
+#include "text-shape.h"
#include "gsl-shell.h"
#include "lua-cpp-utils.h"
#include "gs-types.h"
@@ -62,6 +63,9 @@ static int agg_ellipse_new (lua_State *L);
static int agg_circle_new (lua_State *L);
static int agg_ellipse_free (lua_State *L);
+static int textshape_new (lua_State *L);
+static int textshape_free (lua_State *L);
+
static void path_cmd (draw::path *p, int cmd, struct cmd_call_stack *stack);
static struct path_cmd_reg cmd_table[] = {
@@ -78,6 +82,7 @@ static const struct luaL_Reg draw_functions[] = {
{"path", agg_path_new},
{"ellipse", agg_ellipse_new},
{"circle", agg_circle_new},
+ {"textshape", textshape_new},
{NULL, NULL}
};
@@ -87,6 +92,11 @@ static const struct luaL_Reg agg_path_methods[] = {
{NULL, NULL}
};
+static const struct luaL_Reg textshape_methods[] = {
+ {"__gc", textshape_free},
+ {NULL, NULL}
+};
+
static const struct luaL_Reg agg_ellipse_methods[] = {
{"__gc", agg_ellipse_free},
@@ -243,6 +253,23 @@ agg_ellipse_free (lua_State *L)
return object_free<draw::ellipse>(L, 1, GS_DRAW_ELLIPSE);
}
+int
+textshape_new (lua_State *L)
+{
+ double x = luaL_checknumber(L, 1);
+ double y = luaL_checknumber(L, 2);
+ const char* text = luaL_checkstring(L, 3);
+ double ts = luaL_checknumber(L, 4);
+ new(L, GS_DRAW_TEXTSHAPE) draw::text_shape(x, y, text, ts);
+ return 1;
+}
+
+int
+textshape_free (lua_State *L)
+{
+ return object_free<draw::text_shape>(L, 1, GS_DRAW_TEXTSHAPE);
+}
+
void
draw_register (lua_State *L)
{
@@ -256,6 +283,10 @@ draw_register (lua_State *L)
luaL_register (L, NULL, agg_ellipse_methods);
lua_pop (L, 1);
+ luaL_newmetatable (L, GS_METATABLE(GS_DRAW_TEXTSHAPE));
+ luaL_register (L, NULL, textshape_methods);
+ lua_pop (L, 1);
+
/* gsl module registration */
luaL_register (L, NULL, draw_functions);
}
diff --git a/agg-plot/lua-plot.cpp b/agg-plot/lua-plot.cpp
index 01f3e887..59df3300 100644
--- a/agg-plot/lua-plot.cpp
+++ b/agg-plot/lua-plot.cpp
@@ -67,6 +67,7 @@ static int plot_xlab_angle_get (lua_State *L);
static int plot_ylab_angle_set (lua_State *L);
static int plot_ylab_angle_get (lua_State *L);
static int plot_set_categories (lua_State *L);
+static int plot_set_mini (lua_State *L);
static int plot_sync_mode_get (lua_State *L);
static int plot_sync_mode_set (lua_State *L);
@@ -106,6 +107,7 @@ static const struct luaL_Reg plot_methods[] = {
{"save", bitmap_save_image },
{"save_svg", plot_save_svg },
{"set_categories", plot_set_categories},
+ {"set_mini", plot_set_mini},
{NULL, NULL}
};
@@ -649,6 +651,38 @@ plot_set_categories (lua_State *L)
return 0;
}
+int
+plot_set_mini(lua_State *L)
+{
+ sg_plot* p = object_check<sg_plot>(L, 1, GS_PLOT);
+ const char* placement = luaL_checkstring(L, 2);
+ sg_plot* mp = object_check<sg_plot>(L, 3, GS_PLOT);
+ sg_plot::placement_e pos;
+
+ char letter = placement[0];
+ if (letter == 'r')
+ pos = sg_plot::right;
+ else if (letter == 'l')
+ pos = sg_plot::left;
+ else if (letter == 'b')
+ pos = sg_plot::bottom;
+ else if (letter == 't')
+ pos = sg_plot::top;
+ else
+ return luaL_error (L, "invalid mini plot placement specification.");
+
+ lua_getfenv (L, 1);
+ objref_mref_add (L, -1, (int)pos, 3);
+
+ AGG_LOCK();
+ p->add_mini_plot(mp, pos);
+ AGG_UNLOCK();
+
+ plot_update_raw (L, p, 1);
+
+ return 0;
+}
+
void
plot_register (lua_State *L)
{
diff --git a/agg-plot/plot-auto.h b/agg-plot/plot-auto.h
index 027c0975..17b83c1c 100644
--- a/agg-plot/plot-auto.h
+++ b/agg-plot/plot-auto.h
@@ -41,7 +41,11 @@ public:
virtual ~plot_auto() { };
virtual void add(VertexSource* vs, agg::rgba8& color, bool outline);
- virtual void before_draw() { check_bounding_box(); };
+ virtual void before_draw()
+ {
+ plot<VertexSource, resource_manager>::before_draw();
+ check_bounding_box();
+ };
virtual bool pop_layer();
diff --git a/agg-plot/plot.h b/agg-plot/plot.h
index bc46a9eb..07025ce5 100644
--- a/agg-plot/plot.h
+++ b/agg-plot/plot.h
@@ -89,6 +89,7 @@ public:
typedef virtual_canvas<VertexSource> canvas_type;
enum axis_e { x_axis, y_axis };
+ enum placement_e { right = 0, left = 1, bottom = 2, top = 3 };
struct axis {
str title;
@@ -129,6 +130,8 @@ public:
m_sync_mode(true), m_x_axis(x_axis), m_y_axis(y_axis)
{
compute_user_trans();
+ for (unsigned k = 0; k < 4; k++)
+ m_mini_plot[k] = 0;
};
virtual ~plot()
@@ -146,6 +149,11 @@ public:
str& x_axis_title() { return m_x_axis.title; }
str& y_axis_title() { return m_y_axis.title; }
+ void add_mini_plot(plot* p, placement_e where)
+ {
+ m_mini_plot[where] = p;
+ }
+
axis& get_axis(axis_e axis_dir)
{
return (axis_dir == x_axis ? m_x_axis : m_y_axis);
@@ -169,7 +177,17 @@ public:
void set_limits(const agg::rect_base<double>& r);
virtual void add(VertexSource* vs, agg::rgba8& color, bool outline);
- virtual void before_draw() { };
+ virtual void before_draw() { }
+
+ void get_bounding_rect(agg::rect_base<double>& bb)
+ {
+ before_draw();
+
+ if (m_rect.is_defined())
+ bb = m_rect.rect();
+ else
+ bb = agg::rect_base<double>(0.0, 0.0, 0.0, 0.0);
+ }
template <class Canvas>
void draw(Canvas& canvas, agg::trans_affine& m);
@@ -231,6 +249,9 @@ protected:
void draw_element(item& c, canvas_type &canvas, agg::trans_affine& m);
void draw_axis(canvas_type& can, agg::trans_affine& m);
+ agg::trans_affine draw_mini_plots(canvas_type& canvas,
+ agg::trans_affine& canvas_mtx);
+
agg::trans_affine get_scaled_matrix(agg::trans_affine& canvas_mtx);
void clip_plot_area(canvas_type& canvas, agg::trans_affine& canvas_mtx);
@@ -270,6 +291,7 @@ private:
bool m_sync_mode;
axis m_x_axis, m_y_axis;
+ plot* m_mini_plot[4];
};
static double compute_scale(agg::trans_affine& m)
@@ -333,8 +355,10 @@ template <class Canvas> void plot<VS,RM>::draw(Canvas& _canvas, agg::trans_affin
{
canvas_adapter<Canvas, VS> canvas(&_canvas);
before_draw();
- draw_axis(canvas, canvas_mtx);
- draw_elements(canvas, canvas_mtx);
+
+ agg::trans_affine area_mtx = draw_mini_plots(canvas, canvas_mtx);
+ draw_axis(canvas, area_mtx);
+ draw_elements(canvas, area_mtx);
};
template <class VS, class RM>
@@ -529,11 +553,71 @@ double plot<VS,RM>::draw_axis_m(axis_e dir, units& u,
}
template <class VS, class RM>
+agg::trans_affine plot<VS,RM>::draw_mini_plots(canvas_type& canvas,
+ agg::trans_affine& canvas_mtx)
+{
+ const double sx = canvas_mtx.sx, sy = canvas_mtx.sy;
+ const double pad = 2.0;
+
+ double dxl = 0.0, dxr = 0.0, dyb = 0.0, dyt = 0.0;
+
+ for (int k = 0; k < 4; k++)
+ {
+ plot* mp = m_mini_plot[k];
+
+ if (mp)
+ {
+ agg::rect_base<double> bb;
+ mp->get_bounding_rect(bb);
+
+ double dx = bb.x2 - bb.x1, dy = bb.y2 - bb.y1;
+ double px, py;
+ switch (k)
+ {
+ case right:
+ px = sx - dx + pad;
+ dxr = dx + 2*pad;
+ py = (sy - dy) / 2 + pad;
+ break;
+ case left:
+ px = pad;
+ dxl = dx + 2*pad;
+ py = (sy - dy) / 2 + pad;
+ break;
+ case bottom:
+ py = pad;
+ dyb = dy + 2*pad;
+ px = (sx - dx) / 2 + pad;
+ break;
+ case top:
+ py = sy - dy + pad;
+ dyt = dy + 2*pad;
+ px = (sx - dx) / 2 + pad;
+ break;
+ default:
+ /* */;
+ }
+
+ agg::trans_affine mtx(dx + 2*pad, 0.0, 0.0, dy + 2*pad, px, py);
+
+ mp->before_draw();
+ mp->draw_axis(canvas, mtx);
+ mp->draw_elements(canvas, mtx);
+ }
+ }
+
+ double cpx = canvas_mtx.tx, cpy = canvas_mtx.ty;
+
+ double ssx = sx - (dxl + dxr), ssy = sy - (dyb + dyt);
+ return agg::trans_affine(ssx, 0.0, 0.0, ssy, cpx + dxl, cpy + dyb);
+}
+
+template <class VS, class RM>
void plot<VS,RM>::draw_axis(canvas_type& canvas, agg::trans_affine& canvas_mtx)
{
if (!m_use_units)
{
- const double pad = 4.0;
+ const double pad = 2.0;
m_left_margin = pad;
m_right_margin = pad;
m_bottom_margin = pad;
@@ -573,10 +657,9 @@ void plot<VS,RM>::draw_axis(canvas_type& canvas, agg::trans_affine& canvas_mtx)
const double ppad = 0.02, fpad = 4;
ptr_list<draw::text> labels;
- double dx_label, dy_label;
- dy_label = draw_axis_m(x_axis, m_ux, m_trans, labels, scale, mark, ln);
- dx_label = draw_axis_m(y_axis, m_uy, m_trans, labels, scale, mark, ln);
+ 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);
const double sx = canvas_mtx.sx, sy = canvas_mtx.sy;
const double lsx = (dx_label + 4 * ppad * sx + 2 * fpad) / (1 + 4 * ppad);
diff --git a/agg-plot/rect.h b/agg-plot/rect.h
index 4a5592ba..5faedd7f 100644
--- a/agg-plot/rect.h
+++ b/agg-plot/rect.h
@@ -56,7 +56,8 @@ public:
template <typename T>
agg::rect_base<T> rect_of_slot_matrix (const agg::trans_affine& mtx)
{
- return agg::rect_base<T>(T(mtx.tx), T(mtx.ty), T(mtx.sx + mtx.tx), T(mtx.sy + mtx.ty));
+ T dx = T(mtx.sx + mtx.tx), dy = T(mtx.sy + mtx.ty);
+ return agg::rect_base<T>(T(mtx.tx), T(mtx.ty), dx, dy);
}
#endif
diff --git a/agg-plot/text-shape.h b/agg-plot/text-shape.h
new file mode 100644
index 00000000..326ca9b8
--- /dev/null
+++ b/agg-plot/text-shape.h
@@ -0,0 +1,100 @@
+#ifndef AGGPLOT_TEXT_SHAPE_H
+#define AGGPLOT_TEXT_SHAPE_H
+
+#include "agg_gsv_text.h"
+
+#include "sg_object.h"
+
+typedef sg_object_gen<agg::gsv_text> sg_text_base;
+
+namespace draw {
+
+ class text_shape : public sg_object {
+ public:
+ text_shape(double x, double y, const char* text,
+ double _size = 10.0, double hjustif = 0.0, double vjustif = 0.0):
+ m_sg_text(), m_x(x), m_y(y), m_text(text), m_size(_size),
+ m_scaling(0), m_trans(m_sg_text, identity_matrix), m_stroke(m_trans)
+ {
+ agg::gsv_text& t = m_sg_text.self();
+ t.text(text);
+ t.size(_size);
+
+ const double text_width = t.text_width(), text_height = _size;
+ m_x -= hjustif * text_width;
+ m_y -= vjustif * text_height;
+
+ t.start_point(m_x, m_y);
+
+ m_stroke.line_cap(agg::round_cap);
+ m_stroke.line_join(agg::round_join);
+ }
+
+ virtual void rewind(unsigned path_id)
+ {
+ m_sg_text.self().start_point(m_x, m_y);
+ m_stroke.rewind(path_id);
+ }
+
+ virtual unsigned vertex(double* x, double* y)
+ {
+ return m_stroke.vertex(x, y);
+ }
+
+ virtual void bounding_box(double *x1, double *y1, double *x2, double *y2)
+ {
+ agg::bounding_rect_single(m_sg_text, 0, x1, y1, x2, y2);
+ }
+
+ virtual str write_svg(int id, agg::rgba8 c, double h)
+ {
+ const char* text = m_text.cstr();
+ int txt_size = (int)(m_size * 1.5);
+
+ const agg::trans_affine& m = *m_scaling;
+
+ double x = m_x, y = -m_y;
+ const double dx = m.tx, dy = svg_y_coord(m.ty, h);
+
+ if (is_unit_matrix(m))
+ {
+ x += dx;
+ y += dy;
+ }
+
+ str svgtext = str::print("<text x=\"%g\" y=\"%g\" id=\"text%i\"" \
+ " style=\"font-size:%i\">" \
+ " <tspan id=\"tspan%i\">%s</tspan>" \
+ "</text>",
+ x, y, id, txt_size, id, text);
+
+ str s;
+ if (is_unit_matrix(m))
+ s = svgtext;
+ else
+ s = str::print("<g transform=\"matrix(%g,%g,%g,%g,%g,%g)\">%s</g>",
+ m.sx, m.shx, m.shy, m.sy, dx, dy, svgtext.cstr());
+
+ return s;
+ }
+
+ virtual void apply_transform(const agg::trans_affine& m, double as)
+ {
+ m_stroke.width(1.5 * m.scale());
+ m_trans.transformer(m);
+ m_scaling = &m;
+ }
+
+ private:
+ sg_text_base m_sg_text;
+ double m_x, m_y;
+ str m_text;
+ double m_size;
+
+ const agg::trans_affine* m_scaling;
+ agg::conv_transform<sg_object> m_trans;
+ agg::conv_stroke<agg::conv_transform<sg_object> > m_stroke;
+ };
+}
+
+#endif
diff --git a/agg-plot/text.cpp b/agg-plot/text.cpp
index ad6bd021..1aa63ba6 100644
--- a/agg-plot/text.cpp
+++ b/agg-plot/text.cpp
@@ -62,8 +62,7 @@ namespace draw {
style.printf_add(";fill:%s", rgbstr);
}
- bool need_rotate = (fabs(m.sx - 1.0) > eps || fabs(m.shx) > eps || \
- fabs(m.shy) > eps || fabs(m.sy - 1.0) > eps);
+ bool need_rotate = !is_unit_matrix(m, eps);
int txt_size = (int)(m_text_height * 1.5);
diff --git a/agg-plot/utils.h b/agg-plot/utils.h
index d90febf6..a6a0a5df 100644
--- a/agg-plot/utils.h
+++ b/agg-plot/utils.h
@@ -48,6 +48,12 @@ private:
agg::pod_bvector<T*> m_list;
};
+inline bool is_unit_matrix(const agg::trans_affine& m, double eps = 1.0e-5)
+{
+ return (fabs(m.sx - 1.0) < eps && fabs(m.shx) < eps && \
+ fabs(m.shy) < eps && fabs(m.sy - 1.0) < eps);
+}
+
extern void trans_affine_compose (agg::trans_affine& a,
const agg::trans_affine& b);
generated by cgit v1.2.3 (git 2.39.1) at 2025年09月22日 13:44:49 +0000

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