-rw-r--r-- | agg-plot/Makefile | 2 | ||||
-rw-r--r-- | agg-plot/agg-parse-trans.cpp | 5 | ||||
-rw-r--r-- | agg-plot/canvas_svg.cpp | 42 | ||||
-rw-r--r-- | agg-plot/canvas_svg.h | 80 | ||||
-rw-r--r-- | agg-plot/draw_svg.cpp | 63 | ||||
-rw-r--r-- | agg-plot/draw_svg.h | 95 | ||||
-rw-r--r-- | agg-plot/drawable.h | 4 | ||||
-rw-r--r-- | agg-plot/lua-plot.cpp | 28 | ||||
-rw-r--r-- | agg-plot/lua-text.cpp | 2 | ||||
-rw-r--r-- | agg-plot/my_list.h | 2 | ||||
-rw-r--r-- | agg-plot/plot.h | 147 | ||||
-rw-r--r-- | agg-plot/scalable.h | 24 | ||||
-rw-r--r-- | agg-plot/strpp.h | 48 | ||||
-rw-r--r-- | agg-plot/text.cpp | 67 | ||||
-rw-r--r-- | agg-plot/text.h | 54 | ||||
-rw-r--r-- | agg-plot/trans.h | 98 |
diff --git a/agg-plot/Makefile b/agg-plot/Makefile index 047ddce5..8e40ee19 100644 --- a/agg-plot/Makefile +++ b/agg-plot/Makefile @@ -36,7 +36,7 @@ endif INCLUDES += $(AGG_INCLUDES) -I$(GSH_BASE_DIR) -I$(LUADIR)/src -AGGPLOT_SRC_FILES = $(PLATSUP_SRC_FILES) utils.cpp units.cpp colors.cpp markers.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 +AGGPLOT_SRC_FILES = $(PLATSUP_SRC_FILES) 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 AGGPLOT_OBJ_FILES := $(AGGPLOT_SRC_FILES:%.cpp=%.o) diff --git a/agg-plot/agg-parse-trans.cpp b/agg-plot/agg-parse-trans.cpp index 24bfd33e..8578b01b 100644 --- a/agg-plot/agg-parse-trans.cpp +++ b/agg-plot/agg-parse-trans.cpp @@ -81,7 +81,7 @@ typename context::base_type* build_stroke (lua_State *L, int specindex, typename typename trans<context>::stroke_base& stroke = s->self(); - stroke.width(width); + s->width(width); if (cap_str) { @@ -122,7 +122,6 @@ build_dash (lua_State *L, int specindex, typename context::base_type *obj) typedef typename trans<context>::dash dash_type; dash_type *d = new dash_type(obj); - typename trans<context>::dash_base& dash = d->self(); for (int j = 2; /* */; j += 2) { @@ -137,7 +136,7 @@ build_dash (lua_State *L, int specindex, typename context::base_type *obj) double b = (lua_isnumber (L, -1) ? lua_tonumber (L, -1) : a); - dash.add_dash(a, b); + d->add_dash(a, b); lua_pop (L,1); } else diff --git a/agg-plot/canvas_svg.cpp b/agg-plot/canvas_svg.cpp new file mode 100644 index 00000000..d8f05cb9 --- /dev/null +++ b/agg-plot/canvas_svg.cpp @@ -0,0 +1,42 @@ +#include "canvas_svg.h" + +const double canvas_svg::default_stroke_width = 1.0; + +static void canvas_draw_svg(svg_vs* vs, FILE* f, int id, agg::rgba8 c) +{ + str s = vs->write_svg(id, c); + canvas_svg::writeln(f, s, " "); +} + +static void canvas_draw_outline_svg(svg_vs* vs, FILE* f, int id, agg::rgba8 c) +{ + str path; + svg_property_list* ls = vs->svg_path(path); + str s = svg_stroke_path(path, canvas_svg::default_stroke_width, id, c, ls); + list::free(ls); + canvas_svg::writeln(f, s, " "); +} + +template <> +void canvas_svg::draw<svg_vs>(svg_vs& vs, agg::rgba8 c) +{ + canvas_draw_svg(&vs, m_output, m_current_id++, c); +} + +template <> +void canvas_svg::draw_outline<svg_vs>(svg_vs& vs, agg::rgba8 c) +{ + canvas_draw_outline_svg(&vs, m_output, m_current_id++, c); +} + +template <> +void canvas_svg::draw<drawable>(drawable& vs, agg::rgba8 c) +{ + canvas_draw_svg(&vs, m_output, m_current_id++, c); +} + +template <> +void canvas_svg::draw_outline<drawable>(drawable& vs, agg::rgba8 c) +{ + canvas_draw_outline_svg(&vs, m_output, m_current_id++, c); +} diff --git a/agg-plot/canvas_svg.h b/agg-plot/canvas_svg.h new file mode 100644 index 00000000..b5d70332 --- /dev/null +++ b/agg-plot/canvas_svg.h @@ -0,0 +1,80 @@ +#ifndef CANVAS_SVG_H +#define CANVAS_SVG_H + +#include <stdio.h> + +#include <agg_trans_affine.h> +#include <agg_color_rgba.h> + +#include "defs.h" +#include "strpp.h" +#include "drawable.h" +#include "draw_svg.h" + +static const char *svg_header = \ + "<?xml version=\"1.0\" standalone=\"no\"?>\n" \ + "<svg\n" \ + " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n" \ + " xmlns:cc=\"http://creativecommons.org/ns#\"\n" \ + " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n" \ + " xmlns:svg=\"http://www.w3.org/2000/svg\"\n" \ + " xmlns=\"http://www.w3.org/2000/svg\"\n" \ + " version=\"1.1\"\n" \ + " width=\"%g\"\n" \ + " height=\"%g\"\n" \ + " id=\"svg2\">\n" \ + " <g id=\"layer1\" font-family=\"Helvetica\">\n"; + +static const char *svg_end = " </g>\n" "</svg>\n"; + +class canvas_svg { +public: + canvas_svg(FILE *f) : m_output(f), m_current_id(0) { } + + void clip_box(const agg::rect_base<int>& clip) { } + + void reset_clipping() { } + + template <class VertexSource> + void draw(VertexSource& vs, agg::rgba8 c) + { + str path; + svg_coords_from_vs(&vs, path); + str s = svg_fill_path(path, m_current_id++, c); + writeln(m_output, s, " "); + } + + template <class VertexSource> + void draw_outline(VertexSource& vs, agg::rgba8 c) + { + str path; + svg_coords_from_vs(&vs, path); + str s = svg_stroke_path(path, default_stroke_width, m_current_id++, c); + writeln(m_output, s, " "); + } + + void write_header(double w, double h) { fprintf(m_output, svg_header, w, h); } + void write_end() { fputs(svg_end, m_output); } + + static void writeln(FILE* f, str& s, const char* indent = 0) { + if (str_is_null(&s)) + return; + if (indent) + fputs(indent, f); + fprintf(f, "%s\n", s.cstr()); + } + + static const double default_stroke_width; + +private: + FILE *m_output; + int m_current_id; +}; + +template <> void canvas_svg::draw<svg_vs>(svg_vs& vs, agg::rgba8 c); +template <> void canvas_svg::draw_outline<svg_vs>(svg_vs& vs, agg::rgba8 c); + +template <> void canvas_svg::draw<drawable>(drawable& vs, agg::rgba8 c); +template <> void canvas_svg::draw_outline<drawable>(drawable& vs, agg::rgba8 c); + +#endif diff --git a/agg-plot/draw_svg.cpp b/agg-plot/draw_svg.cpp new file mode 100644 index 00000000..a86da5b1 --- /dev/null +++ b/agg-plot/draw_svg.cpp @@ -0,0 +1,63 @@ +#include "agg_color_rgba.h" + +#include "draw_svg.h" + +const char *svg_path_property_name[] = {"stroke-dasharray"}; + +void format_rgb(char rgbstr[], agg::rgba8 c) +{ + sprintf(rgbstr, "#%02X%02X%02X", (int)c.r, (int)c.g, (int)c.b); +} + +static void append_properties(str& s, svg_property_list* properties) +{ + for (svg_property_list* p = properties; p; p = p->next()) + { + svg_property_item& item = p->content(); + const char* name = svg_path_property_name[item.key]; + s.printf_add(";%s:%s", name, item.value); + } +} + +str svg_stroke_path(str& path_coords, double width, int id, agg::rgba8 c, + svg_property_list* properties) +{ + char rgbstr[8]; + format_rgb(rgbstr, c); + + str s = str::print("<path d=\"%s\" " + "id=\"path%i\" " + "style=\"fill:none;stroke:%s;" + "stroke-width:%gpx;stroke-linecap:butt;" + "stroke-linejoin:miter", + path_coords.cstr(), id, rgbstr, width); + + if (c.a < 255) { + double alpha = (double)c.a / 255; + s.printf_add(";stroke-opacity:%g", alpha); + } + + append_properties(s, properties); + s.append("\" />"); + + return s; +} + +str svg_fill_path(str& path_coords, int id, agg::rgba8 c, + svg_property_list* properties) +{ + char rgbstr[8]; + format_rgb(rgbstr, c); + + double alpha = (double)c.a / 255; + + str s = str::print("<path d=\"%s\" " + "id=\"path%i\" " + "style=\"fill:%s;fill-opacity:%g;stroke:none\" />", + path_coords.cstr(), id, rgbstr, alpha); + + append_properties(s, properties); + s.append("\" />"); + + return s; +} diff --git a/agg-plot/draw_svg.h b/agg-plot/draw_svg.h new file mode 100644 index 00000000..b5fe7889 --- /dev/null +++ b/agg-plot/draw_svg.h @@ -0,0 +1,95 @@ +#ifndef DRAW_SVG_H +#define DRAW_SVG_H + +#include "agg_basics.h" +#include "agg_color_rgba.h" +#include "my_list.h" +#include "strpp.h" + +enum svg_path_property_e { + stroke_dasharray = 0, +}; + +extern const char *svg_path_property_name[]; + +struct svg_property_item { + enum svg_path_property_e key; + const char* value; + + svg_property_item(enum svg_path_property_e k, const char *v) : key(k), value(v) { } +}; + +typedef pod_list<svg_property_item> svg_property_list; + +template <typename VertexSource> +void svg_coords_from_vs(VertexSource* vs, str& s) +{ + unsigned cmd; + double x, y; + const char * const space = " "; + const char *sep = ""; + + vs->rewind(0); + + while ((cmd = vs->vertex(&x, &y))) + { + if (agg::is_move_to(cmd)) { + s.printf_add("%sM %g,%g", sep, x, y); + } else if (agg::is_line_to(cmd)) { + s.printf_add("%s%g,%g", sep, x, y); + } else if (agg::is_close(cmd)) { + s.printf_add("%sz", sep); + } else if (agg::is_curve3(cmd)) { + vs->vertex(&x, &y); + s.printf_add("%s%g,%g", sep, x, y); + } else if (agg::is_curve4(cmd)) { + vs->vertex(&x, &y); + vs->vertex(&x, &y); + s.printf_add("%s%g,%g", sep, x, y); + } + sep = space; + } +} + +template <typename VertexSource> +void svg_curve_coords_from_vs(VertexSource* vs, str& s) +{ + unsigned cmd; + double x, y; + const char * const space = " "; + const char *sep = ""; + bool omit_line_to = false; + + vs->rewind(0); + + while ((cmd = vs->vertex(&x, &y))) + { + if (agg::is_move_to(cmd)) { + s.printf_add("%sM %g,%g", sep, x, y); + omit_line_to = true; + } else if (agg::is_line_to(cmd)) { + s.printf_add("%s%s%g,%g", sep, omit_line_to ? "" : "L ", x, y); + } else if (agg::is_curve4(cmd)) { + double x1 = x, y1 = y; + double x2, y2; + vs->vertex(&x2, &y2); + vs->vertex(&x, &y); + s.printf_add("%sC %g,%g %g,%g %g,%g", sep, x1, y1, x2, x2, x, y); + omit_line_to = false; + } else if (agg::is_curve3(cmd)) { + double x1 = x, y1 = y; + vs->vertex(&x, &y); + s.printf_add("%sQ %g,%g %g,%g", sep, x1, y1, x, y); + omit_line_to = false; + } else if (agg::is_close(cmd)) { + s.printf_add("%sz", sep); + } + sep = space; + } +} + +extern str svg_stroke_path(str& path_coords, double width, int id, agg::rgba8 c, svg_property_list* properties = 0); +extern str svg_fill_path(str& path_coords, int id, agg::rgba8 c, svg_property_list* properties = 0); +extern void format_rgb(char rgbstr[], agg::rgba8 c); + +#endif diff --git a/agg-plot/drawable.h b/agg-plot/drawable.h index a4fb7df6..d3ddfa82 100644 --- a/agg-plot/drawable.h +++ b/agg-plot/drawable.h @@ -7,6 +7,7 @@ #include "agg_trans_affine.h" #include "agg_conv_transform.h" #include "agg_bounding_rect.h" +#include "agg_color_rgba.h" struct drawable : public vertex_source { virtual void bounding_box(double *x1, double *y1, double *x2, double *y2) = 0; @@ -25,6 +26,9 @@ class boxed_drawable : public drawable { virtual unsigned vertex(double* x, double* y) { return m_object->vertex(x, y); }; virtual void apply_transform(const agg::trans_affine& m, double as) { m_object->apply_transform(m, as); }; + virtual str write_svg(int id, agg::rgba8 c) { return m_object->write_svg(id, c); } + virtual svg_property_list* svg_path(str& s) { return m_object->svg_path(s); } + virtual void bounding_box(double *x1, double *y1, double *x2, double *y2) { m_object->bounding_box(x1, y1, x2, y2); diff --git a/agg-plot/lua-plot.cpp b/agg-plot/lua-plot.cpp index d953ac50..b1bf2a75 100644 --- a/agg-plot/lua-plot.cpp +++ b/agg-plot/lua-plot.cpp @@ -38,6 +38,7 @@ extern "C" { #include "drawable.h" #include "resource-manager.h" #include "agg-parse-trans.h" +#include "canvas_svg.h" __BEGIN_DECLS @@ -58,6 +59,7 @@ static int plot_set_limits (lua_State *L); static int plot_push_layer (lua_State *L); static int plot_pop_layer (lua_State *L); static int plot_clear (lua_State *L); +static int plot_save_svg (lua_State *L); static int plot_sync_mode_get (lua_State *L); static int plot_sync_mode_set (lua_State *L); @@ -95,6 +97,7 @@ static const struct luaL_Reg plot_methods[] = { {"poplayer", plot_pop_layer }, {"clear", plot_clear }, {"save", bitmap_save_image }, + {"save_svg", plot_save_svg }, {NULL, NULL} }; @@ -421,6 +424,31 @@ plot_clear (lua_State *L) return 0; } +int +plot_save_svg (lua_State *L) +{ + lua_plot *p = object_check<lua_plot>(L, 1, GS_PLOT); + const char *filename = lua_tostring(L, 2); + double w = luaL_optnumber(L, 3, 800.0); + double h = luaL_optnumber(L, 4, 600.0); + + if (!filename) + return gs_type_error(L, 2, "string"); + + FILE* f = fopen(filename, "w"); + if (!f) + return luaL_error(L, "cannot open filename: %s", filename); + + canvas_svg canvas(f); + agg::trans_affine m(w, 0.0, 0.0, -h, 0.0, h); + canvas.write_header(w, h); + p->draw(canvas, m); + canvas.write_end(); + fclose(f); + + return 0; +} + static int plot_pad_mode_set (lua_State *L) { lua_plot *p = object_check<lua_plot>(L, 1, GS_PLOT); diff --git a/agg-plot/lua-text.cpp b/agg-plot/lua-text.cpp index 065211a7..91a606bc 100644 --- a/agg-plot/lua-text.cpp +++ b/agg-plot/lua-text.cpp @@ -66,7 +66,7 @@ int agg_text_new (lua_State *L) { double size = luaL_optnumber (L, 1, 10.0); - double width = luaL_optnumber (L, 2, 1.0); + double width = luaL_optnumber (L, 2, 1.0) + 0.7; new(L, GS_DRAW_TEXT) draw::text(size, width); return 1; } diff --git a/agg-plot/my_list.h b/agg-plot/my_list.h index fdaebb72..12880d69 100644 --- a/agg-plot/my_list.h +++ b/agg-plot/my_list.h @@ -46,7 +46,7 @@ namespace list { pod_list<T> *n; for (/* */; p; p = n) { - n = p->m_next; + n = p->next(); delete p; } } diff --git a/agg-plot/plot.h b/agg-plot/plot.h index 53348c1b..67507494 100644 --- a/agg-plot/plot.h +++ b/agg-plot/plot.h @@ -25,12 +25,16 @@ #include "utils.h" #include "my_list.h" +#include "strpp.h" #include "drawable.h" #include "canvas.h" #include "units.h" #include "resource-manager.h" #include "colors.h" #include "rect.h" +#include "canvas_svg.h" +#include "trans.h" +#include "text.h" #include "agg_array.h" #include "agg_bounding_rect.h" @@ -72,14 +76,10 @@ public: m_root_layer(), m_layers(), m_current_layer(&m_root_layer), 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_buf(), + m_use_units(use_units), m_pad_units(false), m_title(), m_sync_mode(true) { compute_user_trans(); - - m_title_buf.capacity(32); - m_title = m_title_buf.data(); - m_title[0] = '0円'; }; virtual ~plot() @@ -94,7 +94,7 @@ public: }; void set_title(const char *text); - const char *title() const { return m_title; }; + const char *title() const { return m_title.cstr(); }; void set_units(bool use_units); bool use_units() const { return m_use_units; }; @@ -104,7 +104,8 @@ public: virtual void add(vertex_source* vs, agg::rgba8& color, bool outline); virtual void before_draw() { }; - void draw(canvas &canvas, agg::trans_affine& m); + template <class Canvas> + void draw(Canvas &canvas, agg::trans_affine& m); virtual bool push_layer(); virtual bool pop_layer(); @@ -139,14 +140,21 @@ public: bool pad_mode() { return m_pad_units; }; protected: - void draw_elements(canvas &canvas, agg::trans_affine& m); - void draw_element(item& c, canvas &canvas, agg::trans_affine& m); - void draw_title(canvas& canvas, agg::trans_affine& m); - void draw_axis(canvas& can, agg::trans_affine& m); + template <typename Canvas> + void draw_elements(Canvas &canvas, agg::trans_affine& m); + + template <typename Canvas> + void draw_element(item& c, Canvas &canvas, agg::trans_affine& m); + + template <typename Canvas> + void draw_title(Canvas& canvas, agg::trans_affine& m); + + template <typename Canvas> + void draw_axis(Canvas& can, agg::trans_affine& m); agg::trans_affine get_scaled_matrix(agg::trans_affine& canvas_mtx); - void clip_plot_area(canvas &canvas, agg::trans_affine& canvas_mtx); + template <class Canvas> void clip_plot_area(Canvas &canvas, agg::trans_affine& canvas_mtx); void compute_user_trans(); @@ -176,15 +184,14 @@ protected: private: bool m_pad_units; - agg::pod_vector<char> m_title_buf; - char *m_title; + str m_title; bool m_sync_mode; }; static double compute_scale(agg::trans_affine& m) { - return min(m.sy, m.sx) / 480.0; + return min(fabs(m.sy), fabs(m.sx)) / 480.0; } static double @@ -218,10 +225,7 @@ void plot<VS,RM>::add(VS* vs, agg::rgba8& color, bool outline) template <class VS, class RM> void plot<VS,RM>::set_title(const char *text) { - unsigned int len = strlen(text); - m_title_buf.resize(len+1); - m_title = m_title_buf.data(); - memcpy (m_title, text, len+1); + str_copy_c(&m_title, text); } template <class VS, class RM> @@ -248,7 +252,7 @@ void plot<VS,RM>::clear_drawing_queue() } template <class VS, class RM> -void plot<VS,RM>::draw(canvas &canvas, agg::trans_affine& canvas_mtx) +template <class Canvas> void plot<VS,RM>::draw(Canvas &canvas, agg::trans_affine& canvas_mtx) { before_draw(); draw_title(canvas, canvas_mtx); @@ -258,9 +262,9 @@ void plot<VS,RM>::draw(canvas &canvas, agg::trans_affine& canvas_mtx) }; template <class VS, class RM> -void plot<VS,RM>::draw_title(canvas &canvas, agg::trans_affine& canvas_mtx) +template <class Canvas> void plot<VS,RM>::draw_title(Canvas &canvas, agg::trans_affine& canvas_mtx) { - double xt = 0.5, yt = 1; + double xt = 0.5, yt = 1.05; agg::trans_affine m; this->viewport_scale(m); @@ -268,27 +272,17 @@ void plot<VS,RM>::draw_title(canvas &canvas, agg::trans_affine& canvas_mtx) double scale = compute_scale(canvas_mtx); - agg::gsv_text title; - agg::conv_stroke<agg::gsv_text> titlestroke(title); - - title.size(12.0 * scale); - title.text(m_title); - - titlestroke.width(std_line_width(scale)); - titlestroke.line_cap(agg::round_cap); - titlestroke.line_join(agg::round_join); + draw::text title(12.0 * scale, std_line_width(scale)); + title.set_text(m_title.cstr()); + title.hjustif(0.5); + title.set_point(xt, yt); + title.apply_transform(m, 1.0); - m.transform(&xt, &yt); - - xt += -title.text_width() / 2; - yt += 10.0 * scale; - - title.start_point(xt, yt); - canvas.draw(titlestroke, agg::rgba(0, 0, 0)); + canvas.draw(*(drawable *) &title, agg::rgba(0, 0, 0)); } template<class VS, class RM> -void plot<VS,RM>::draw_element(item& c, canvas &canvas, agg::trans_affine& m) +template <class Canvas> void plot<VS,RM>::draw_element(item& c, Canvas &canvas, agg::trans_affine& m) { VS& vs = c.vertex_source(); vs.apply_transform(m, 1.0); @@ -309,7 +303,7 @@ agg::trans_affine plot<VS,RM>::get_scaled_matrix(agg::trans_affine& canvas_mtx) } template<class VS, class RM> -void plot<VS,RM>::clip_plot_area(canvas &canvas, agg::trans_affine& canvas_mtx) +template <class Canvas> void plot<VS,RM>::clip_plot_area(Canvas &canvas, agg::trans_affine& canvas_mtx) { if (this->clip_is_active()) { @@ -322,7 +316,7 @@ void plot<VS,RM>::clip_plot_area(canvas &canvas, agg::trans_affine& canvas_mtx) } template<class VS, class RM> -void plot<VS,RM>::draw_elements(canvas &canvas, agg::trans_affine& canvas_mtx) +template <class Canvas> void plot<VS,RM>::draw_elements(Canvas &canvas, agg::trans_affine& canvas_mtx) { agg::trans_affine m = get_scaled_matrix(canvas_mtx); @@ -400,7 +394,7 @@ void plot<VS,RM>::compute_user_trans() } template <class VS, class RM> -void plot<VS,RM>::draw_axis(canvas &canvas, agg::trans_affine& canvas_mtx) +template <class Canvas> void plot<VS,RM>::draw_axis(Canvas &canvas, agg::trans_affine& canvas_mtx) { typedef agg::path_storage path_type; typedef agg::conv_dash<agg::conv_transform<path_type>, agg::vcgen_markers_term> dash_type; @@ -420,12 +414,15 @@ void plot<VS,RM>::draw_axis(canvas &canvas, agg::trans_affine& canvas_mtx) agg::path_storage ln; agg::conv_transform<path_type> lntr(ln, m); - dash_type lndash(lntr); - agg::conv_stroke<dash_type> lns(lndash); + svg_proxy<agg::conv_transform<path_type> > lntrsvg(&lntr); + trans<svg_context>::dash lndashsvg(&lntrsvg); + trans<svg_context>::stroke lns(&lndashsvg); const double yeps = 1.0e-3; const double xeps = 1.0e-3; + double line_width = std_line_width(scale); + { int jinf = m_uy.begin(), jsup = m_uy.end(); for (int j = jinf; j <= jsup; j++) @@ -434,32 +431,26 @@ void plot<VS,RM>::draw_axis(canvas &canvas, agg::trans_affine& canvas_mtx) this->m_trans.transform(&x, &y); if (y >= - yeps && y <= 1.0 + yeps) { - agg::gsv_text lab; - agg::conv_stroke<agg::gsv_text> labs(lab); + draw::text label(12.0 * scale, line_width); char lab_text[32]; - double xlab = 0, ylab = y; - lab.size(12.0 * scale); m_uy.mark_label(lab_text, 32, j); - lab.text(lab_text); - labs.width(std_line_width(scale)); + label.set_text(lab_text); - m.transform(&xlab, &ylab); + label.hjustif(1.0); + label.vjustif(0.5); + label.set_point(-0.02, y); + label.apply_transform(m, 1.0); - xlab += -lab.text_width() - 10.0 * scale; - ylab += -5.0 * scale; - - lab.start_point(xlab, ylab); - canvas.draw(labs, agg::rgba(0, 0, 0)); + canvas.draw(*(drawable *) &label, agg::rgba(0, 0, 0)); mark.move_to(0.0, y); mark.line_to(-0.01, y); - if (j > jinf && j < jsup) - { - ln.move_to(0.0, y); - ln.line_to(1.0, y); - } + if (j > jinf && j < jsup) { + ln.move_to(0.0, y); + ln.line_to(1.0, y); + } } } } @@ -468,44 +459,38 @@ void plot<VS,RM>::draw_axis(canvas &canvas, agg::trans_affine& canvas_mtx) int jinf = m_ux.begin(), jsup = m_ux.end(); for (int j = jinf; j <= jsup; j++) { - double x = m_ux.mark_value(j), y = m_uy.mark_value(j); + double x = m_ux.mark_value(j), y = 0.0; this->m_trans.transform(&x, &y); if (x >= - xeps && x <= 1.0 + xeps) { - agg::gsv_text lab; - agg::conv_stroke<agg::gsv_text> labs(lab); + draw::text label(12.0 * scale, line_width); char lab_text[32]; - double xlab = x, ylab = 0; - lab.size(12.0 * scale); m_ux.mark_label(lab_text, 32, j); - lab.text(lab_text); - labs.width(std_line_width(scale)); - - m.transform(&xlab, &ylab); + label.set_text(lab_text); - xlab += -lab.text_width()/2.0; - ylab += -24.0 * scale; + label.hjustif(0.5); + label.vjustif(1.6); + label.set_point(x, 0); + label.apply_transform(m, 1.0); - lab.start_point(xlab, ylab); - canvas.draw(labs, agg::rgba(0, 0, 0)); + canvas.draw(*(drawable *) &label, agg::rgba(0, 0, 0)); mark.move_to(x, 0.0); mark.line_to(x, -0.01); - if (j > jinf && j < jsup) - { - ln.move_to(x, 0.0); - ln.line_to(x, 1.0); - } + if (j > jinf && j < jsup) { + ln.move_to(x, 0.0); + ln.line_to(x, 1.0); + } } } } - lndash.add_dash(7.0, 3.0); + lndashsvg.add_dash(7.0, 3.0); lns.width(std_line_width(scale, 0.25)); - canvas.draw(lns, colors::black); + canvas.draw(*(svg_vs *) &lns, colors::black); mark_stroke.width(std_line_width(scale, 0.75)); canvas.draw(mark_stroke, colors::black); diff --git a/agg-plot/scalable.h b/agg-plot/scalable.h index 745323da..29002645 100644 --- a/agg-plot/scalable.h +++ b/agg-plot/scalable.h @@ -22,12 +22,34 @@ #define AGGPLOT_SCALABLE_H #include "agg_trans_affine.h" +#include "draw_svg.h" +#include "strpp.h" + +struct svg_vs { -struct vertex_source { virtual void rewind(unsigned path_id) = 0; virtual unsigned vertex(double* x, double* y) = 0; + + virtual str write_svg(int id, agg::rgba8 c) { + str path; + svg_property_list* ls = this->svg_path(path); + str s = svg_fill_path(path, id, c, ls); + list::free(ls); + return s; + } + + virtual svg_property_list* svg_path(str& s) { + svg_coords_from_vs(this, s); + return 0; + } + + virtual ~svg_vs() { } +}; + +struct vertex_source : public svg_vs { virtual void apply_transform(const agg::trans_affine& m, double as) = 0; virtual bool affine_compose(agg::trans_affine& m) { return false; }; + virtual ~vertex_source() { }; }; diff --git a/agg-plot/strpp.h b/agg-plot/strpp.h new file mode 100644 index 00000000..f1fdfe80 --- /dev/null +++ b/agg-plot/strpp.h @@ -0,0 +1,48 @@ +#ifndef STRPP_H +#define STRPP_H + +#include "str.h" + +class str : public _str { +public: + str(int sz = 64) { str_init(this, sz); } + str(const char *s) { str_init_from_c(this, s); } + str(const str& s) { str_init_from_str(this, &s); } + + ~str() { str_free(this); } + + const str& operator = (const str& s) { + str_copy(this, &s); + return *this; + } + + const char* cstr() const { return CSTR(this); } + + void append(const str& s, int sep = 0) { str_append(this, &s, sep); } + void append(const char* s, int sep = 0) { str_append_c(this, s, sep); } + + void printf(const char* fmt, ...) { + va_list ap; + va_start (ap, fmt); + str_vprintf (this, fmt, 0, ap); + va_end (ap); + } + + void printf_add(const char* fmt, ...) { + va_list ap; + va_start (ap, fmt); + str_vprintf (this, fmt, 1, ap); + va_end (ap); + } + + static str print(const char* fmt, ...) { + va_list ap; + va_start (ap, fmt); + str s; + str_vprintf (&s, fmt, 0, ap); + va_end (ap); + return s; + } +}; + +#endif diff --git a/agg-plot/text.cpp b/agg-plot/text.cpp index b1935d1b..1a382c37 100644 --- a/agg-plot/text.cpp +++ b/agg-plot/text.cpp @@ -1,4 +1,6 @@ +#include "agg_trans_affine.h" + #include "text.h" namespace draw { @@ -19,13 +21,17 @@ namespace draw { void text::apply_transform(const agg::trans_affine& m, double as) { - double& x = m_matrix.tx; - double& y = m_matrix.ty; + m_user_matrix.tx = m_x; + m_user_matrix.ty = m_y; + + m.transform(&m_user_matrix.tx, &m_user_matrix.ty); - x = m_x; - y = m_y; + m_matrix = m_user_matrix; - m.transform(&x, &y); + if (m.sy < 0.0) { + m_matrix.shy *= -1.0; + m_matrix.sy *= -1.0; + } m_stroke.approximation_scale(as); } @@ -36,4 +42,55 @@ namespace draw { *x1 = *x2 = m_x; *y1 = *y2 = m_y; } + + str + text::write_svg(int id, agg::rgba8 c) + { + const agg::trans_affine& m = m_user_matrix; + const double eps = 1.0e-6; + str s; + + if (str_is_null(&m_text_buf)) + return s; + + str style; + int hjust = lrint(m_hjustif * 2.0); + if (hjust == 1) + style.append(";text-anchor:middle"); + else if (hjust >= 2) + style.append(";text-anchor:end"); + + if (c.r != 0 || c.g != 0 || c.b != 0) { + char rgbstr[8]; + format_rgb(rgbstr, c); + 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); + + int txt_size = (int)(m_text_height * 1.5); + + double x = 0.0, y = m_vjustif * m_text_height * 1.2; + if (!need_rotate) { + x += m.tx; + y += m.ty; + } + + const char* cont = m_text_buf.cstr(); + str txt = str::print("<text x=\"%g\" y=\"%g\" id=\"text%i\"" \ + " style=\"font-size:%i%s\">" \ + " <tspan x=\"%g\" y=\"%g\" id=\"tspan%i\">%s</tspan>" \ + "</text>", + x, y, id, txt_size, style.cstr(), x, y, id, cont); + + if (need_rotate) { + s = str::print("<g transform=\"matrix(%g,%g,%g,%g,%g,%g)\">%s</g>", + m.sx, m.shx, m.shy, m.sy, m.tx, m.ty, txt.cstr()); + } else { + s = txt; + } + + return s; + } } diff --git a/agg-plot/text.h b/agg-plot/text.h index 7988fda7..20f56121 100644 --- a/agg-plot/text.h +++ b/agg-plot/text.h @@ -16,12 +16,13 @@ namespace draw { typedef agg::conv_stroke<vs_trans_text> vs_stroked_text; agg::trans_affine m_matrix; + agg::trans_affine m_user_matrix; vs_text m_text; vs_trans_text m_trans; vs_stroked_text m_stroke; - agg::pod_vector<char> m_text_buf; + str m_text_buf; double m_x, m_y; double m_angle; @@ -34,63 +35,52 @@ namespace draw { public: text(double size = 10.0, double width = 1.0): - m_matrix(), m_text(), m_trans(m_text, m_matrix), m_stroke(m_trans), + m_matrix(), m_user_matrix(), + m_text(), m_trans(m_text, m_matrix), m_stroke(m_trans), m_text_buf(), m_x(0.0), m_y(0.0), m_angle(0.0), m_text_width(0.0), m_text_height(size), m_hjustif(0.0), m_vjustif(0.0) { - m_text_buf.capacity(32); - m_text_buf[0] = '0円'; - - m_stroke.width(width + 0.5); - m_stroke.line_cap(agg::round_cap); - m_stroke.line_join(agg::round_join); + m_stroke.width(width); m_text.size(size); - }; + } - void angle(double th) - { + void angle(double th) { double c = cos(th), s = sin(th); m_angle = th; - m_matrix.sx = c; - m_matrix.shx = -s; - m_matrix.shy = s; - m_matrix.sy = c; - }; + m_user_matrix.sx = c; + m_user_matrix.shx = -s; + m_user_matrix.shy = s; + m_user_matrix.sy = c; + } double angle() const { return m_angle; }; - void set_text(const char *txt) - { - size_t len = strlen (txt); - m_text_buf.capacity(len+1); - memcpy (m_text_buf.data(), txt, len+1); - + void set_text(const char *txt) { + str_copy_c(&m_text_buf, txt); m_text.text(txt); m_text_width = m_text.text_width(); - }; + } - const char * get_text() const - { - return m_text_buf.data(); - }; + const char * get_text() const { return m_text_buf.cstr(); } - void set_point(double x, double y) - { + void set_point(double x, double y) { m_x = x; m_y = y; - }; + } - void hjustif(double hj) { m_hjustif = hj; }; - void vjustif(double vj) { m_vjustif = vj; }; + void hjustif(double hj) { m_hjustif = hj; } + void vjustif(double vj) { m_vjustif = vj; } virtual void rewind(unsigned path_id); virtual unsigned vertex(double* x, double* y); virtual void apply_transform(const agg::trans_affine& m, double as); virtual void bounding_box(double *x1, double *y1, double *x2, double *y2); + virtual str write_svg(int id, agg::rgba8 c); + vs_text& self() { return m_text; }; }; } diff --git a/agg-plot/trans.h b/agg-plot/trans.h index 71727d12..54fb7eb4 100644 --- a/agg-plot/trans.h +++ b/agg-plot/trans.h @@ -6,6 +6,7 @@ #include "markers.h" #include "utils.h" #include "resource-manager.h" +#include "draw_svg.h" #include "agg_trans_affine.h" #include "agg_path_storage.h" @@ -34,7 +35,6 @@ struct scalable_context { typedef scalable base_type; }; - struct drawable_context { template <class conv_type, bool approx> @@ -57,13 +57,65 @@ struct trans { typedef typename context::base_type base_type; typedef agg::conv_stroke<base_type> stroke_base; - typedef typename context::template adapter<stroke_base, true> stroke; + typedef typename context::template adapter<stroke_base, true> vs_stroke; + + class stroke : public vs_stroke { + public: + stroke(base_type* src) : vs_stroke(src), m_width(1.0) { } + + void width(double w) { + this->m_output.width(w); + m_width = w; + } + + virtual str write_svg(int id, agg::rgba8 c) { + str path; + svg_property_list* ls = this->m_source->svg_path(path); + str s = svg_stroke_path(path, m_width, id, c, ls); + list::free(ls); + return s; + } + + private: + double m_width; + }; typedef agg::conv_curve<base_type> curve_base; - typedef typename context::template adapter<curve_base, true> curve; + typedef typename context::template adapter<curve_base, true> vs_curve; + + class curve : public vs_curve { + public: + curve(base_type* src) : vs_curve(src) { } + + virtual svg_property_list* svg_path(str& s) { + svg_curve_coords_from_vs(this->m_source, s); + return 0; + } + }; typedef agg::conv_dash<base_type> dash_base; - typedef typename context::template adapter<dash_base, false> dash; + typedef typename context::template adapter<dash_base, false> vs_dash; + + class dash : public vs_dash { + public: + dash(base_type* src) : vs_dash(src), m_dasharray(16) { } + + virtual svg_property_list* svg_path(str& s) { + svg_property_list* ls = this->m_source->svg_path(s); + svg_property_item item(stroke_dasharray, this->m_dasharray.cstr()); + ls = new svg_property_list(item, ls); + return ls; + } + + void add_dash(double a, double b) { + this->m_output.add_dash(a, b); + this->m_dasharray.append("", ','); + this->m_dasharray.printf_add("%g,%g", a, b); + } + + private: + str m_dasharray; + }; typedef agg::conv_contour<base_type> extend_base; typedef typename context::template adapter<extend_base, true> extend; @@ -126,4 +178,42 @@ struct trans { }; }; +template <class T> +class svg_proxy : public svg_vs { +protected: + T* m_base; + +public: + svg_proxy(T* src): svg_vs(), m_base(src) { } + + virtual void rewind(unsigned path_id) { m_base->rewind(path_id); } + virtual unsigned vertex(double* x, double* y) { return m_base->vertex(x, y); } + + T& self() { return *m_base; } +}; + +struct svg_context { + + template <class conv_type, bool approx> + class adapter : public svg_vs + { + protected: + conv_type m_output; + svg_vs* m_source; + + public: + adapter(svg_vs* src): m_output(*src), m_source(src) { } + + template <class init_type> + adapter(svg_vs* src, init_type& val): m_output(*src, val), m_source(src) { } + + virtual void rewind(unsigned path_id) { m_output.rewind(path_id); } + virtual unsigned vertex(double* x, double* y) { return m_output.vertex(x, y); } + + conv_type& self() { return m_output; }; + }; + + typedef svg_vs base_type; +}; + #endif |