pre6 commit, just a day late:)
[dia.git] / plug-ins / pgf / render_pgf.c
blob9004fa8b7c02d2b06b7152ffdb9654836b2d4968
1 /* -*- Mode: C; c-basic-offset: 4 -*- */
2 /* Dia -- an diagram creation/manipulation program
3 * Copyright (C) 1998 Alexander Larsson
5 * render_pgf.c: Exporting module/plug-in to TeX PGF package
6 * Copyright (C) 2005 Moritz Kirmse
7 * Originally derived from render_pstricks.c (pstricks plug-in)
8 * Copyright (C) 2000 Jacek Pliszka <pliszka@fuw.edu.pl>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 Implementation choices:
28 The PGF package is written with the idea in mind that the typesetting software will
29 (usually) do a better and more beautiful job than the user.
31 This export filter respects thes and therefore some export features are special:
33 -text is NOT escaped: (La)TeX will interpret this code.
34 Therefore text size wil not be consistent and bounding boxes will not work.
35 When text is inside a box (as for example in the UML modules), the result wil not
36 be as expected.
38 -some arrows from the PGF-library are used (latex, stealth and to)
39 for these arrows, size selection and bounding box won't work
41 -the rounded corners for polyline-paths are slightly different:
42 the radius measure is not the radius of the arc,
43 but the length cut off at the angle from each segment of the polyline
44 however the PGF native corner rounding was implemented, since I observed a discontinuous
45 line thickness at the interface between the segments and arcs
47 TODO:
48 -Image exporting function
49 -Implement PGF basic layer throughout
50 -Implement all the Arrow styles
54 #include <config.h>
56 #include <string.h>
57 #include <time.h>
58 #include <math.h>
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62 #include <errno.h>
64 #include <glib/gprintf.h>
66 #include "intl.h"
67 #include "render_pgf.h"
68 #include "message.h"
69 #include "diagramdata.h"
70 #include "dia_image.h"
71 #include "filter.h"
72 #include "arrows.h"
74 #define POINTS_in_INCH 28.346
75 #define DTOSTR_BUF_SIZE G_ASCII_DTOSTR_BUF_SIZE
76 #define pgf_dtostr(buf,d) \
77 g_ascii_formatd(buf,sizeof(buf),"%f",d)
78 #define pgf_itostr(buf,i) \
79 g_sprintf(buf,"%d",i)
81 static void begin_render(DiaRenderer *self);
82 static void end_render(DiaRenderer *self);
83 static void set_linewidth(DiaRenderer *self, real linewidth);
84 static void set_linecaps(DiaRenderer *self, LineCaps mode);
85 static void set_linejoin(DiaRenderer *self, LineJoin mode);
86 static void set_linestyle(DiaRenderer *self, LineStyle mode);
87 static void set_dashlength(DiaRenderer *self, real length);
88 static void set_fillstyle(DiaRenderer *self, FillStyle mode);
89 static void set_font(DiaRenderer *self, DiaFont *font, real height);
90 static void draw_line(DiaRenderer *self,
91 Point *start, Point *end,
92 Color *line_color);
93 static void draw_polyline(DiaRenderer *self,
94 Point *points, int num_points,
95 Color *line_color);
96 static void draw_rounded_polyline (DiaRenderer *self,
97 Point *points, int num_points,
98 Color *color, real radius);
99 static void draw_polygon(DiaRenderer *self,
100 Point *points, int num_points,
101 Color *line_color);
102 static void fill_polygon(DiaRenderer *self,
103 Point *points, int num_points,
104 Color *line_color);
105 static void draw_rect(DiaRenderer *self,
106 Point *ul_corner, Point *lr_corner,
107 Color *color);
108 static void fill_rect(DiaRenderer *self,
109 Point *ul_corner, Point *lr_corner,
110 Color *color);
111 static void draw_rounded_rect(DiaRenderer *self,
112 Point *ul_corner, Point *lr_corner,
113 Color *color, real radius);
114 static void fill_rounded_rect(DiaRenderer *self,
115 Point *ul_corner, Point *lr_corner,
116 Color *color, real radius);
117 static void draw_arc(DiaRenderer *self,
118 Point *center,
119 real width, real height,
120 real angle1, real angle2,
121 Color *color);
122 static void fill_arc(DiaRenderer *self,
123 Point *center,
124 real width, real height,
125 real angle1, real angle2,
126 Color *color);
127 static void draw_ellipse(DiaRenderer *self,
128 Point *center,
129 real width, real height,
130 Color *color);
131 static void fill_ellipse(DiaRenderer *self,
132 Point *center,
133 real width, real height,
134 Color *color);
135 static void draw_bezier(DiaRenderer *self,
136 BezPoint *points,
137 int numpoints,
138 Color *color);
139 static void fill_bezier(DiaRenderer *self,
140 BezPoint *points, /* Last point must be same as first point */
141 int numpoints,
142 Color *color);
143 static void draw_string(DiaRenderer *self,
144 const char *text,
145 Point *pos, Alignment alignment,
146 Color *color);
147 static void draw_image(DiaRenderer *self,
148 Point *point,
149 real width, real height,
150 DiaImage image);
152 static void draw_line_with_arrows(DiaRenderer *renderer, Point *start, Point *end,
153 real line_width, Color *line_color,
154 Arrow *start_arrow, Arrow *end_arrow);
155 static void draw_arc_with_arrows(DiaRenderer *renderer, Point *start, Point *end, Point *midpoint,
156 real line_width, Color *color,
157 Arrow *start_arrow, Arrow *end_arrow);
158 static void draw_polyline_with_arrows(DiaRenderer *renderer, Point *points, int num_points,
159 real line_width, Color *color,
160 Arrow *start_arrow, Arrow *end_arrow);
161 static void draw_rounded_polyline_with_arrows(DiaRenderer *renderer,
162 Point *points, int num_points, real line_width, Color *color,
163 Arrow *start_arrow, Arrow *end_arrow, real radius);
164 static void draw_bezier_with_arrows(DiaRenderer *renderer, BezPoint *points, int num_points,
165 real line_width, Color *color,
166 Arrow *start_arrow, Arrow *end_arrow);
168 /*store the higher level arrow functions for arrows not (yet) implemented in this PGF macro*/
169 void (*orig_draw_line_with_arrows) (DiaRenderer *renderer, Point *start, Point *end,
170 real line_width, Color *line_color,
171 Arrow *start_arrow, Arrow *end_arrow);
173 void (*orig_draw_arc_with_arrows) (DiaRenderer *renderer, Point *start, Point *end, Point *midpoint,
174 real line_width, Color *color,
175 Arrow *start_arrow, Arrow *end_arrow);
177 void (*orig_draw_polyline_with_arrows) (DiaRenderer *renderer, Point *points, int num_points,
178 real line_width, Color *color,
179 Arrow *start_arrow, Arrow *end_arrow);
181 void (*orig_draw_rounded_polyline_with_arrows) (DiaRenderer *renderer,
182 Point *points, int num_points, real line_width, Color *color,
183 Arrow *start_arrow, Arrow *end_arrow, real radius);
185 void (*orig_draw_bezier_with_arrows) (DiaRenderer *renderer, BezPoint *points, int num_points,
186 real line_width, Color *color,
187 Arrow *start_arrow, Arrow *end_arrow);
191 static void pgf_renderer_class_init (PgfRendererClass *klass);
193 static gpointer parent_class = NULL;
195 GType
196 pgf_renderer_get_type (void)
198 static GType object_type = 0;
200 if (!object_type)
202 static const GTypeInfo object_info =
204 sizeof (PgfRendererClass),
205 (GBaseInitFunc) NULL,
206 (GBaseFinalizeFunc) NULL,
207 (GClassInitFunc) pgf_renderer_class_init,
208 NULL, /* class_finalize */
209 NULL, /* class_data */
210 sizeof (PgfRenderer),
211 0, /* n_preallocs */
212 NULL /* init */
215 object_type = g_type_register_static (DIA_TYPE_RENDERER,
216 "PGFRenderer",
217 &object_info, 0);
220 return object_type;
223 static void
224 pgf_renderer_finalize (GObject *object)
226 G_OBJECT_CLASS (parent_class)->finalize (object);
229 static void
230 pgf_renderer_class_init (PgfRendererClass *klass)
232 GObjectClass *object_class = G_OBJECT_CLASS (klass);
233 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
235 parent_class = g_type_class_peek_parent (klass);
237 object_class->finalize = pgf_renderer_finalize;
239 renderer_class->begin_render = begin_render;
240 renderer_class->end_render = end_render;
242 renderer_class->set_linewidth = set_linewidth;
243 renderer_class->set_linecaps = set_linecaps;
244 renderer_class->set_linejoin = set_linejoin;
245 renderer_class->set_linestyle = set_linestyle;
246 renderer_class->set_dashlength = set_dashlength;
247 renderer_class->set_fillstyle = set_fillstyle;
248 renderer_class->set_font = set_font;
250 renderer_class->draw_line = draw_line;
251 renderer_class->draw_polyline = draw_polyline;
253 /*problem: the round angles behave slightly differently under PGF:
254 the radius measure is not the radius, but the length cut off at the angle
255 from each segment of the polyline
256 however, to keep the inherited round corner generation, this command can be commented out*/
257 renderer_class->draw_rounded_polyline = draw_rounded_polyline;
259 renderer_class->draw_polygon = draw_polygon;
260 renderer_class->fill_polygon = fill_polygon;
262 renderer_class->draw_rect = draw_rect;
263 renderer_class->fill_rect = fill_rect;
265 renderer_class->draw_rounded_rect = draw_rounded_rect;
266 renderer_class->fill_rounded_rect = fill_rounded_rect;
268 renderer_class->draw_arc = draw_arc;
269 renderer_class->fill_arc = fill_arc;
271 renderer_class->draw_ellipse = draw_ellipse;
272 renderer_class->fill_ellipse = fill_ellipse;
274 renderer_class->draw_bezier = draw_bezier;
275 renderer_class->fill_bezier = fill_bezier;
277 /* to keep the dia arrows instead of the native PGF ones, comment out this block of commands */
278 orig_draw_line_with_arrows = renderer_class->draw_line_with_arrows;
279 renderer_class->draw_line_with_arrows = draw_line_with_arrows;
280 orig_draw_arc_with_arrows = renderer_class->draw_arc_with_arrows;
281 renderer_class->draw_arc_with_arrows = draw_arc_with_arrows;
282 orig_draw_polyline_with_arrows = renderer_class->draw_polyline_with_arrows;
283 renderer_class->draw_polyline_with_arrows = draw_polyline_with_arrows;
284 orig_draw_rounded_polyline_with_arrows = renderer_class->draw_rounded_polyline_with_arrows;
285 renderer_class->draw_rounded_polyline_with_arrows = draw_rounded_polyline_with_arrows;
286 orig_draw_bezier_with_arrows = renderer_class->draw_bezier_with_arrows;
287 renderer_class->draw_bezier_with_arrows = draw_bezier_with_arrows;
289 renderer_class->draw_string = draw_string;
291 renderer_class->draw_image = draw_image;
295 static void
296 set_line_color(PgfRenderer *renderer,Color *color)
298 gchar red_buf[DTOSTR_BUF_SIZE];
299 gchar green_buf[DTOSTR_BUF_SIZE];
300 gchar blue_buf[DTOSTR_BUF_SIZE];
302 fprintf(renderer->file, "\\definecolor{dialinecolor}{rgb}{%s, %s, %s}\n",
303 pgf_dtostr(red_buf, (gdouble) color->red),
304 pgf_dtostr(green_buf, (gdouble) color->green),
305 pgf_dtostr(blue_buf, (gdouble) color->blue) );
306 fprintf(renderer->file,"\\pgfsetstrokecolor{dialinecolor}\n");
309 static void
310 set_fill_color(PgfRenderer *renderer,Color *color)
312 gchar red_buf[DTOSTR_BUF_SIZE];
313 gchar green_buf[DTOSTR_BUF_SIZE];
314 gchar blue_buf[DTOSTR_BUF_SIZE];
316 fprintf(renderer->file, "\\definecolor{dialinecolor}{rgb}{%s, %s, %s}\n",
317 pgf_dtostr(red_buf, (gdouble) color->red),
318 pgf_dtostr(green_buf, (gdouble) color->green),
319 pgf_dtostr(blue_buf, (gdouble) color->blue) );
320 fprintf(renderer->file,"\\pgfsetfillcolor{dialinecolor}\n");
323 static void
324 begin_render(DiaRenderer *self)
328 static void
329 end_render(DiaRenderer *self)
331 PgfRenderer *renderer = PGF_RENDERER(self);
333 fprintf(renderer->file,"\\end{tikzpicture}\n");
334 fclose(renderer->file);
337 static void
338 set_linewidth(DiaRenderer *self, real linewidth)
339 { /* 0 == hairline (thinnest possible line on device) **/
340 PgfRenderer *renderer = PGF_RENDERER(self);
341 gchar d_buf[DTOSTR_BUF_SIZE];
344 fprintf(renderer->file, "\\pgfsetlinewidth{%s\\du}\n",
345 pgf_dtostr(d_buf, (gdouble) linewidth) );
348 static void
349 set_linecaps(DiaRenderer *self, LineCaps mode)
351 PgfRenderer *renderer = PGF_RENDERER(self);
353 switch(mode) {
354 case LINECAPS_BUTT:
355 fprintf(renderer->file, "\\pgfsetbuttcap\n");
356 break;
357 case LINECAPS_ROUND:
358 fprintf(renderer->file, "\\pgfsetroundcap\n");
359 break;
360 case LINECAPS_PROJECTING:
361 fprintf(renderer->file, "\\pgfsetrectcap\n");
362 break;
363 default:
364 fprintf(renderer->file, "\\pgfsetbuttcap\n");
369 static void
370 set_linejoin(DiaRenderer *self, LineJoin mode)
372 PgfRenderer *renderer = PGF_RENDERER(self);
373 int ps_mode;
375 switch(mode) {
376 case LINEJOIN_MITER:
377 fprintf(renderer->file, "\\pgfsetmiterjoin\n");
378 break;
379 case LINEJOIN_ROUND:
380 fprintf(renderer->file, "\\pgfsetroundjoin\n");
381 break;
382 case LINEJOIN_BEVEL:
383 fprintf(renderer->file, "\\pgfsetbeveljoin\n");
384 break;
385 default:
386 fprintf(renderer->file, "\\pgfsetmiterjoin\n");
391 static void
392 set_linestyle(DiaRenderer *self, LineStyle mode)
394 PgfRenderer *renderer = PGF_RENDERER(self);
395 real hole_width;
396 gchar dash_length_buf[DTOSTR_BUF_SIZE];
397 gchar dot_length_buf[DTOSTR_BUF_SIZE];
398 gchar hole_width_buf[DTOSTR_BUF_SIZE];
400 renderer->saved_line_style = mode;
402 switch(mode) {
403 case LINESTYLE_SOLID:
404 fprintf(renderer->file, "\\pgfsetdash{}{0pt}\n");
405 break;
406 case LINESTYLE_DASHED:
407 pgf_dtostr(dash_length_buf,renderer->dash_length);
408 fprintf(renderer->file, "\\pgfsetdash{{%s\\du}{%s\\du}}{0\\du}\n",
409 dash_length_buf,
410 dash_length_buf);
411 break;
412 case LINESTYLE_DASH_DOT:
413 hole_width = (renderer->dash_length - renderer->dot_length) / 2.0;
414 pgf_dtostr(hole_width_buf,hole_width);
415 pgf_dtostr(dot_length_buf,renderer->dot_length);
416 pgf_dtostr(dash_length_buf,renderer->dash_length);
417 fprintf(renderer->file, "\\pgfsetdash{{%s\\du}{%s\\du}{%s\\du}{%s\\du}}{0cm}\n",
418 dash_length_buf,
419 hole_width_buf,
420 dot_length_buf,
421 hole_width_buf );
422 break;
423 case LINESTYLE_DASH_DOT_DOT:
424 hole_width = (renderer->dash_length - 2.0*renderer->dot_length) / 3.0;
425 pgf_dtostr(hole_width_buf,hole_width);
426 pgf_dtostr(dot_length_buf,renderer->dot_length);
427 pgf_dtostr(dash_length_buf,renderer->dash_length);
428 fprintf(renderer->file, "\\pgfsetdash{{%s\\du}{%s\\du}{%s\\du}{%s\\du}{%s\\du}{%s\\du}}{0cm}\n",
429 dash_length_buf,
430 hole_width_buf,
431 dot_length_buf,
432 hole_width_buf,
433 dot_length_buf,
434 hole_width_buf );
435 break;
436 case LINESTYLE_DOTTED:
437 pgf_dtostr(dot_length_buf,renderer->dot_length);
438 fprintf(renderer->file, "\\pgfsetdash{{\\pgflinewidth}{%s\\du}}{0cm}\n", dot_length_buf);
439 break;
443 static void
444 set_dashlength(DiaRenderer *self, real length)
445 { /* dot = 20% of len */
446 PgfRenderer *renderer = PGF_RENDERER(self);
448 if (length<0.001)
449 length = 0.001;
451 renderer->dash_length = length;
452 renderer->dot_length = length*0.2;
454 set_linestyle(self, renderer->saved_line_style);
457 static void
458 set_fillstyle(DiaRenderer *self, FillStyle mode)
460 switch(mode) {
461 case FILLSTYLE_SOLID:
462 break;
463 default:
464 message_error("pgf_renderer: Unsupported fill mode specified!\n");
468 static void
469 set_font(DiaRenderer *self, DiaFont *font, real height)
471 PgfRenderer *renderer = PGF_RENDERER(self);
472 gchar d_buf[DTOSTR_BUF_SIZE];
474 fprintf(renderer->file, "%% setfont left to latex\n");
477 static void
478 draw_line(DiaRenderer *self,
479 Point *start, Point *end,
480 Color *line_color)
482 PgfRenderer *renderer = PGF_RENDERER(self);
483 gchar sx_buf[DTOSTR_BUF_SIZE];
484 gchar sy_buf[DTOSTR_BUF_SIZE];
485 gchar ex_buf[DTOSTR_BUF_SIZE];
486 gchar ey_buf[DTOSTR_BUF_SIZE];
488 set_line_color(renderer,line_color);
490 fprintf(renderer->file, "\\draw (%s\\du,%s\\du)--(%s\\du,%s\\du);\n",
491 pgf_dtostr(sx_buf,start->x),
492 pgf_dtostr(sy_buf,start->y),
493 pgf_dtostr(ex_buf,end->x),
494 pgf_dtostr(ey_buf,end->y) );
497 static void
498 draw_polyline(DiaRenderer *self,
499 Point *points, int num_points,
500 Color *line_color)
502 PgfRenderer *renderer = PGF_RENDERER(self);
503 int i;
504 gchar px_buf[DTOSTR_BUF_SIZE];
505 gchar py_buf[DTOSTR_BUF_SIZE];
507 set_line_color(renderer,line_color);
508 fprintf(renderer->file, "\\draw (%s\\du,%s\\du)",
509 pgf_dtostr(px_buf,points[0].x),
510 pgf_dtostr(py_buf,points[0].y) );
512 for (i=1;i<num_points;i++) {
513 fprintf(renderer->file, "--(%s\\du,%s\\du)",
514 pgf_dtostr(px_buf,points[i].x),
515 pgf_dtostr(py_buf,points[i].y) );
518 fprintf(renderer->file, ";\n");
521 /*problem: the round angles behave slightly differently under PGF:
522 the radius measure is not the radius, but the length cut off at the angle
523 from each segment of the polyline*/
524 static void draw_rounded_polyline (DiaRenderer *self,
525 Point *points, int num_points,
526 Color *color, real radius)
528 gchar rad_buf[DTOSTR_BUF_SIZE];
530 PgfRenderer *renderer = PGF_RENDERER(self);
531 pgf_dtostr(rad_buf, (gdouble) radius);
532 fprintf(renderer->file, "{\\pgfsetcornersarced{\\pgfpoint{%s\\du}{%s\\du}}",
533 rad_buf, rad_buf);
534 draw_polyline(self,points,num_points,color);
535 fprintf(renderer->file, "}");
538 static void
539 pgf_polygon(PgfRenderer *renderer,
540 Point *points, gint num_points,
541 Color *line_color, gboolean filled)
543 gint i;
544 gchar px_buf[DTOSTR_BUF_SIZE];
545 gchar py_buf[DTOSTR_BUF_SIZE];
547 if (!filled) {set_line_color(renderer,line_color);}
548 else {set_fill_color(renderer,line_color);}
551 fprintf(renderer->file, "\\%s (%s\\du,%s\\du)",
552 (filled?"fill":"draw"),
553 pgf_dtostr(px_buf,points[0].x),
554 pgf_dtostr(py_buf,points[0].y) );
556 for (i=1;i<num_points;i++) {
557 fprintf(renderer->file, "--(%s\\du,%s\\du)",
558 pgf_dtostr(px_buf,points[i].x),
559 pgf_dtostr(py_buf,points[i].y) );
561 fprintf(renderer->file,"--cycle;\n");
564 static void
565 draw_polygon(DiaRenderer *self,
566 Point *points, int num_points,
567 Color *line_color)
569 PgfRenderer *renderer = PGF_RENDERER(self);
571 pgf_polygon(renderer,points,num_points,line_color,FALSE);
574 static void
575 fill_polygon(DiaRenderer *self,
576 Point *points, int num_points,
577 Color *line_color)
579 PgfRenderer *renderer = PGF_RENDERER(self);
581 pgf_polygon(renderer,points,num_points,line_color,TRUE);
584 static void
585 pgf_rect(PgfRenderer *renderer,
586 Point *ul_corner, Point *lr_corner,
587 Color *color, gboolean filled)
589 gchar ulx_buf[DTOSTR_BUF_SIZE];
590 gchar uly_buf[DTOSTR_BUF_SIZE];
591 gchar lrx_buf[DTOSTR_BUF_SIZE];
592 gchar lry_buf[DTOSTR_BUF_SIZE];
594 if (!filled) {set_line_color(renderer,color);}
595 else {set_fill_color(renderer,color);}
597 pgf_dtostr(ulx_buf, (gdouble) ul_corner->x);
598 pgf_dtostr(uly_buf, (gdouble) ul_corner->y);
599 pgf_dtostr(lrx_buf, (gdouble) lr_corner->x);
600 pgf_dtostr(lry_buf, (gdouble) lr_corner->y);
602 fprintf(renderer->file, "\\%s (%s\\du,%s\\du)--(%s\\du,%s\\du)--(%s\\du,%s\\du)--(%s\\du,%s\\du)--cycle;\n",
603 (filled?"fill":"draw"),
604 ulx_buf, uly_buf,
605 ulx_buf, lry_buf,
606 lrx_buf, lry_buf,
607 lrx_buf, uly_buf );
610 static void
611 draw_rect(DiaRenderer *self,
612 Point *ul_corner, Point *lr_corner,
613 Color *color)
615 PgfRenderer *renderer = PGF_RENDERER(self);
617 pgf_rect(renderer,ul_corner,lr_corner,color,FALSE);
620 static void
621 fill_rect(DiaRenderer *self,
622 Point *ul_corner, Point *lr_corner,
623 Color *color)
625 PgfRenderer *renderer = PGF_RENDERER(self);
627 pgf_rect(renderer,ul_corner,lr_corner,color,TRUE);
630 static void
631 draw_rounded_rect(DiaRenderer *self,
632 Point *ul_corner, Point *lr_corner,
633 Color *color, real radius)
635 gchar rad_buf[DTOSTR_BUF_SIZE];
637 PgfRenderer *renderer = PGF_RENDERER(self);
638 pgf_dtostr(rad_buf, (gdouble) radius);
639 fprintf(renderer->file, "{\\pgfsetcornersarced{\\pgfpoint{%s\\du}{%s\\du}}",
640 rad_buf, rad_buf);
641 pgf_rect(renderer,ul_corner,lr_corner,color,FALSE);
642 fprintf(renderer->file, "}");
645 static void
646 fill_rounded_rect(DiaRenderer *self,
647 Point *ul_corner, Point *lr_corner,
648 Color *color, real radius)
650 PgfRenderer *renderer = PGF_RENDERER(self);
651 gchar rad_buf[DTOSTR_BUF_SIZE];
652 pgf_dtostr(rad_buf, (gdouble) radius);
653 fprintf(renderer->file, "{\\pgfsetcornersarced{\\pgfpoint{%s\\du}{%s\\du}}",
654 rad_buf, rad_buf);
655 pgf_rect(renderer,ul_corner,lr_corner,color,TRUE);
656 fprintf(renderer->file, "}");
660 static void
661 pgf_arc(PgfRenderer *renderer,
662 Point *center,
663 real width, real height,
664 real angle1, real angle2,
665 Color *color,int filled)
667 double radius1,radius2;
668 int ang1,ang2;
669 gchar stx_buf[DTOSTR_BUF_SIZE];
670 gchar sty_buf[DTOSTR_BUF_SIZE];
671 gchar cx_buf[DTOSTR_BUF_SIZE];
672 gchar cy_buf[DTOSTR_BUF_SIZE];
673 gchar r1_buf[DTOSTR_BUF_SIZE];
674 gchar r2_buf[DTOSTR_BUF_SIZE];
675 gchar sqrt_buf[DTOSTR_BUF_SIZE];
676 gchar angle1_buf[DTOSTR_BUF_SIZE];
677 gchar angle2_buf[DTOSTR_BUF_SIZE];
679 radius1=(double) width/2.0;
680 radius2=(double) height/2.0;
682 pgf_dtostr(stx_buf,center->x+ radius1*cos(angle1*.017453));
683 pgf_dtostr(sty_buf,center->y- radius2*sin(angle1*.017453));
684 pgf_dtostr(cx_buf,center->x);
685 pgf_dtostr(cy_buf,center->y);
686 pgf_dtostr(r1_buf,radius1);
687 pgf_dtostr(r2_buf,radius2);
688 pgf_dtostr(sqrt_buf,sqrt(radius1*radius1+radius2*radius2));
689 ang1=(int)angle1;
690 ang2=(int)angle2;
691 ang2=ang1+(360+ang2-ang1)%360;
692 pgf_itostr(angle1_buf,360-ang1);
693 pgf_itostr(angle2_buf,360-ang2);
695 if (!filled) {set_line_color(renderer,color);}
696 else {set_fill_color(renderer,color);}
699 fprintf(renderer->file,"\\pgfpathmoveto{\\pgfpoint{%s\\du}{%s\\du}}\n",
700 stx_buf, sty_buf);
701 fprintf(renderer->file,"\\pgfpatharc{%s}{%s}{%s\\du/%s\\du}\n",
702 angle1_buf, angle2_buf,
703 r1_buf, r2_buf);
705 if (filled)
706 fprintf(renderer->file, "\\pgfusepath{fill}\n");
707 else
708 fprintf(renderer->file, "\\pgfusepath{stroke}\n");
711 static void
712 draw_arc(DiaRenderer *self,
713 Point *center,
714 real width, real height,
715 real angle1, real angle2,
716 Color *color)
718 PgfRenderer *renderer = PGF_RENDERER(self);
720 pgf_arc(renderer,center,width,height,angle1,angle2,color,0);
723 static void
724 fill_arc(DiaRenderer *self,
725 Point *center,
726 real width, real height,
727 real angle1, real angle2,
728 Color *color)
730 PgfRenderer *renderer = PGF_RENDERER(self);
732 pgf_arc(renderer,center,width,height,angle1,angle2,color,1);
735 static void
736 pgf_ellipse(PgfRenderer *renderer,
737 Point *center,
738 real width, real height,
739 Color *color, gboolean filled)
741 gchar cx_buf[DTOSTR_BUF_SIZE];
742 gchar cy_buf[DTOSTR_BUF_SIZE];
743 gchar width_buf[DTOSTR_BUF_SIZE];
744 gchar height_buf[DTOSTR_BUF_SIZE];
746 if (!filled) {set_line_color(renderer,color);}
747 else {set_fill_color(renderer,color);}
749 /* "\\%sdraw (%s\\du,%s\\du) ellipse (%s\\du and %s\\du)\n", */
750 fprintf(renderer->file,
751 "\\pgfpathellipse{\\pgfpoint{%s\\du}{%s\\du}}"
752 "{\\pgfpoint{%s\\du}{0\\du}}"
753 "{\\pgfpoint{0\\du}{%s\\du}}\n"
754 "\\pgfusepath{%s}\n",
755 pgf_dtostr(cx_buf,center->x),
756 pgf_dtostr(cy_buf,center->y),
757 pgf_dtostr(width_buf,width/2.0),
758 pgf_dtostr(height_buf,height/2.0),
759 (filled?"fill":"stroke") );
762 static void
763 draw_ellipse(DiaRenderer *self,
764 Point *center,
765 real width, real height,
766 Color *color)
768 PgfRenderer *renderer = PGF_RENDERER(self);
770 pgf_ellipse(renderer,center,width,height,color,FALSE);
773 static void
774 fill_ellipse(DiaRenderer *self,
775 Point *center,
776 real width, real height,
777 Color *color)
779 PgfRenderer *renderer = PGF_RENDERER(self);
781 pgf_ellipse(renderer,center,width,height,color,TRUE);
784 static void
785 pgf_bezier(PgfRenderer *renderer,
786 BezPoint *points,
787 gint numpoints,
788 Color *color, gboolean filled)
790 gint i;
791 gchar p1x_buf[DTOSTR_BUF_SIZE];
792 gchar p1y_buf[DTOSTR_BUF_SIZE];
793 gchar p2x_buf[DTOSTR_BUF_SIZE];
794 gchar p2y_buf[DTOSTR_BUF_SIZE];
795 gchar p3x_buf[DTOSTR_BUF_SIZE];
796 gchar p3y_buf[DTOSTR_BUF_SIZE];
798 if (!filled) {set_line_color(renderer,color);}
799 else {set_fill_color(renderer,color);}
801 if (points[0].type != BEZ_MOVE_TO)
802 g_warning("first BezPoint must be a BEZ_MOVE_TO");
804 fprintf(renderer->file, "\\pgfpathmoveto{\\pgfpoint{%s\\du}{%s\\du}}\n",
805 pgf_dtostr(p1x_buf,points[0].p1.x),
806 pgf_dtostr(p1y_buf,points[0].p1.y) );
808 for (i = 1; i < numpoints; i++)
809 switch (points[i].type) {
810 case BEZ_MOVE_TO:
811 g_warning("only first BezPoint can be a BEZ_MOVE_TO");
812 break;
813 case BEZ_LINE_TO:
814 fprintf(renderer->file, "\\pgfpathlineto{\\pgfpoint{%s\\du}{%s\\du}}\n",
815 pgf_dtostr(p1x_buf,points[i].p1.x),
816 pgf_dtostr(p1y_buf,points[i].p1.y) );
817 break;
818 case BEZ_CURVE_TO:
819 fprintf(renderer->file, "\\pgfpathcurveto{\\pgfpoint{%s\\du}{%s\\du}}"
820 "{\\pgfpoint{%s\\du}{%s\\du}}"
821 "{\\pgfpoint{%s\\du}{%s\\du}}\n",
822 pgf_dtostr(p1x_buf,points[i].p1.x),
823 pgf_dtostr(p1y_buf,points[i].p1.y),
824 pgf_dtostr(p2x_buf,points[i].p2.x),
825 pgf_dtostr(p2y_buf,points[i].p2.y),
826 pgf_dtostr(p3x_buf,points[i].p3.x),
827 pgf_dtostr(p3y_buf,points[i].p3.y) );
828 break;
831 if (filled)
832 fprintf(renderer->file, "\\pgfusepath{fill}\n");
834 /* fill[fillstyle=solid,fillcolor=diafillcolor,linecolor=diafillcolor]}\n"); */
835 else
836 fprintf(renderer->file, "\\pgfusepath{stroke}\n");
839 static void
840 draw_bezier(DiaRenderer *self,
841 BezPoint *points,
842 int numpoints, /* numpoints = 4+3*n, n=>0 */
843 Color *color)
845 PgfRenderer *renderer = PGF_RENDERER(self);
847 pgf_bezier(renderer,points,numpoints,color,FALSE);
852 static void
853 fill_bezier(DiaRenderer *self,
854 BezPoint *points, /* Last point must be same as first point */
855 int numpoints,
856 Color *color)
858 PgfRenderer *renderer = PGF_RENDERER(self);
860 pgf_bezier(renderer,points,numpoints,color,TRUE);
863 static int
864 set_arrows(PgfRenderer *renderer, Arrow *start_arrow, Arrow *end_arrow)
866 int modified = 2|1; /*=3*/
867 fprintf(renderer->file, "%% was here!!!\n");
868 switch (start_arrow->type)
870 case ARROW_NONE:
871 break;
872 case ARROW_LINES:
873 fprintf(renderer->file, "\\pgfsetarrowsstart{to}\n");
874 break;
875 case ARROW_FILLED_TRIANGLE:
876 fprintf(renderer->file, "\\pgfsetarrowsstart{latex}\n");
877 break;
878 case ARROW_FILLED_CONCAVE:
879 fprintf(renderer->file, "\\pgfsetarrowsstart{stealth}\n");
880 break;
881 default:
882 modified ^= 2;
884 if (modified & 2) start_arrow->type = ARROW_NONE;
886 switch (end_arrow->type)
888 case ARROW_NONE:
889 break;
890 case ARROW_LINES:
891 fprintf(renderer->file, "\\pgfsetarrowsend{to}\n");
892 break;
893 case ARROW_FILLED_TRIANGLE:
894 fprintf(renderer->file, "\\pgfsetarrowsend{latex}\n");
895 break;
896 case ARROW_FILLED_CONCAVE:
897 fprintf(renderer->file, "\\pgfsetarrowsend{stealth}\n");
898 break;
899 default:
900 modified ^= 1;
902 if (modified & 1) end_arrow->type = ARROW_NONE;
904 return modified; /* =0 if no native arrow is used */
907 static void
908 draw_line_with_arrows(DiaRenderer *self, Point *start, Point *end,
909 real line_width, Color *line_color,
910 Arrow *start_arrow, Arrow *end_arrow)
912 int nat_arr;
913 Arrow st_arrow=*start_arrow;
914 Arrow e_arrow=*end_arrow;
915 PgfRenderer *renderer = PGF_RENDERER(self);
916 fprintf(renderer->file, "{\n");
917 set_fill_color(renderer, line_color);
918 nat_arr = set_arrows(renderer, &st_arrow, &e_arrow);
919 if (nat_arr != 0)
921 /* static void set_linewidth(self, line_width);
922 draw_line(self, start, end, line_width, color);*/
923 orig_draw_line_with_arrows(self, start, end, line_width, line_color, NULL, NULL);
925 fprintf(renderer->file, "}\n");
926 if (nat_arr != 3)
928 orig_draw_line_with_arrows(self, start, end, line_width, line_color, &st_arrow, &e_arrow);
933 static void
934 draw_arc_with_arrows(DiaRenderer *self, Point *start, Point *end, Point *midpoint,
935 real line_width, Color *color,
936 Arrow *start_arrow, Arrow *end_arrow)
938 int nat_arr;
939 Arrow st_arrow=*start_arrow;
940 Arrow e_arrow=*end_arrow;
941 PgfRenderer *renderer = PGF_RENDERER(self);
942 fprintf(renderer->file, "{\n");
943 set_fill_color(renderer, color);
944 nat_arr = set_arrows(renderer, &st_arrow, &e_arrow);
945 if (nat_arr != 0)
947 orig_draw_arc_with_arrows(self, start, end, midpoint, line_width, color, NULL, NULL);
949 fprintf(renderer->file, "}\n");
950 if (nat_arr != 3)
952 orig_draw_arc_with_arrows(self, start, end, midpoint, line_width, color, &st_arrow, &e_arrow);
956 static void
957 draw_polyline_with_arrows(DiaRenderer *self, Point *points, int num_points,
958 real line_width, Color *color,
959 Arrow *start_arrow, Arrow *end_arrow)
961 int nat_arr;
962 Arrow st_arrow=*start_arrow;
963 Arrow e_arrow=*end_arrow;
964 PgfRenderer *renderer = PGF_RENDERER(self);
965 fprintf(renderer->file, "{\n");
966 set_fill_color(renderer, color);
967 nat_arr = set_arrows(renderer, &st_arrow, &e_arrow);
968 if (nat_arr != 0)
970 orig_draw_polyline_with_arrows(self, points, num_points, line_width, color, NULL, NULL);
972 fprintf(renderer->file, "}\n");
973 if (nat_arr != 3)
975 orig_draw_polyline_with_arrows(self, points, num_points, line_width, color, &st_arrow, &e_arrow);
979 static void
980 draw_rounded_polyline_with_arrows(DiaRenderer *self,
981 Point *points, int num_points, real line_width, Color *color,
982 Arrow *start_arrow, Arrow *end_arrow, real radius)
984 int nat_arr;
985 Arrow st_arrow=*start_arrow;
986 Arrow e_arrow=*end_arrow;
987 PgfRenderer *renderer = PGF_RENDERER(self);
988 fprintf(renderer->file, "{\n");
989 set_fill_color(renderer, color);
990 nat_arr = set_arrows(renderer, &st_arrow, &e_arrow);
991 if (nat_arr != 0)
993 orig_draw_rounded_polyline_with_arrows(self, points, num_points,
994 line_width, color, NULL, NULL, radius);
996 fprintf(renderer->file, "}\n");
997 if (nat_arr != 3)
999 orig_draw_rounded_polyline_with_arrows(self, points, num_points,
1000 line_width, color, &st_arrow, &e_arrow, radius);
1004 static void
1005 draw_bezier_with_arrows(DiaRenderer *self, BezPoint *points, int num_points,
1006 real line_width, Color *color,
1007 Arrow *start_arrow, Arrow *end_arrow)
1009 int nat_arr;
1010 Arrow st_arrow=*start_arrow;
1011 Arrow e_arrow=*end_arrow;
1012 PgfRenderer *renderer = PGF_RENDERER(self);
1013 fprintf(renderer->file, "{\n");
1014 set_fill_color(renderer, color);
1015 nat_arr = set_arrows(renderer, &st_arrow, &e_arrow);
1016 if (nat_arr != 0)
1018 orig_draw_bezier_with_arrows(self, points, num_points, line_width, color, &st_arrow, &e_arrow);
1020 fprintf(renderer->file, "}\n");
1021 if (nat_arr != 3)
1023 orig_draw_bezier_with_arrows(self, points, num_points, line_width, color, NULL, NULL);
1031 /* Do we really want to do this? What if the text is intended as
1032 * TeX text? Jacek says leave it as a TeX string. TeX uses should know
1033 * how to escape stuff anyway. Later versions will get an export option.
1035 * Later (hb): given the UML issue bug #112377 an manually tweaking
1036 * is not possible as the # is added before anything a user can add. So IMO
1037 * we need to want this. If there later (much later?) is an export it probably
1038 * shouldn't produce broken output either ...
1040 static gchar *
1041 tex_escape_string(const gchar *src)
1043 GString *dest = g_string_sized_new(g_utf8_strlen(src, -1));
1044 gchar *p;
1046 if (!g_utf8_validate(src, -1, NULL)) {
1047 message_error(_("Not valid UTF8"));
1048 return g_strdup(src);
1051 p = (char *) src;
1052 while (*p != '\0') {
1053 switch (*p) {
1054 case '%': g_string_append(dest, "\\%"); break;
1055 case '#': g_string_append(dest, "\\#"); break;
1056 case '$': g_string_append(dest, "\\$"); break;
1057 case '&': g_string_append(dest, "\\&"); break;
1058 case '~': g_string_append(dest, "\\~{}"); break;
1059 case '_': g_string_append(dest, "\\_"); break;
1060 case '^': g_string_append(dest, "\\^{}"); break;
1061 case '\\': g_string_append(dest, "\\ensuremath{\\backslash}"); break;
1062 case '{': g_string_append(dest, "\\{"); break;
1063 case '}': g_string_append(dest, "\\}"); break;
1064 case '[': g_string_append(dest, "\\ensuremath{[}"); break;
1065 case ']': g_string_append(dest, "\\ensuremath{]}"); break;
1066 default:
1067 /* if we really have utf8 append the whole 'glyph' */
1068 g_string_append_len(dest, p, g_utf8_skip[(unsigned char)*p]);
1070 p = g_utf8_next_char(p);
1073 p = dest->str;
1074 g_string_free(dest, FALSE);
1075 return p;
1078 static void
1079 draw_string(DiaRenderer *self,
1080 const char *text,
1081 Point *pos, Alignment alignment,
1082 Color *color)
1084 PgfRenderer *renderer = PGF_RENDERER(self);
1085 gchar *escaped = tex_escape_string(text);
1086 gchar px_buf[DTOSTR_BUF_SIZE];
1087 gchar py_buf[DTOSTR_BUF_SIZE];
1089 set_line_color(renderer,color);
1091 fprintf(renderer->file,"\\node");
1092 switch (alignment) {
1093 case ALIGN_LEFT:
1094 fprintf(renderer->file,"[anchor=west]");
1095 break;
1096 case ALIGN_CENTER:
1097 break;
1098 case ALIGN_RIGHT:
1099 fprintf(renderer->file,"[anchor=east]");
1100 break;
1102 fprintf(renderer->file," at (%s\\du,%s\\du){%s};\n",
1103 pgf_dtostr(px_buf,pos->x),
1104 pgf_dtostr(py_buf,pos->y),
1105 escaped);
1106 g_free(escaped);
1109 static void
1110 draw_image(DiaRenderer *self,
1111 Point *point,
1112 real width, real height,
1113 DiaImage image)
1115 PgfRenderer *renderer = PGF_RENDERER(self);
1117 fprintf(renderer->file, "%% image rendering not supported");
1120 /* --- export filter interface --- */
1121 static void
1122 export_pgf(DiagramData *data, const gchar *filename,
1123 const gchar *diafilename, void* user_data)
1125 PgfRenderer *renderer;
1126 FILE *file;
1127 time_t time_now;
1128 double scale;
1129 Rectangle *extent;
1130 const char *name;
1131 gchar el_buf[DTOSTR_BUF_SIZE];
1132 gchar er_buf[DTOSTR_BUF_SIZE];
1133 gchar eb_buf[DTOSTR_BUF_SIZE];
1134 gchar et_buf[DTOSTR_BUF_SIZE];
1135 gchar scale1_buf[DTOSTR_BUF_SIZE];
1136 gchar scale2_buf[DTOSTR_BUF_SIZE];
1138 Color initial_color;
1140 file = fopen(filename, "wb");
1142 if (file==NULL) {
1143 message_error(_("Can't open output file %s: %s\n"),
1144 dia_message_filename(filename), strerror(errno));
1147 renderer = g_object_new(PGF_TYPE_RENDERER, NULL);
1149 renderer->pagenum = 1;
1150 renderer->file = file;
1152 renderer->dash_length = 1.0;
1153 renderer->dot_length = 0.2;
1154 renderer->saved_line_style = LINESTYLE_SOLID;
1156 time_now = time(NULL);
1157 extent = &data->extents;
1159 scale = POINTS_in_INCH * data->paper.scaling;
1161 name = g_get_user_name();
1163 fprintf(file,
1164 "%% Graphic for TeX using PGF\n"
1165 "%% Title: %s\n"
1166 "%% Creator: Dia v%s\n"
1167 "%% CreationDate: %s"
1168 "%% For: %s\n"
1169 "%% \\usepackage{tikz}\n"
1170 "%% The following commands are not supported in PSTricks at present\n"
1171 "%% We define them conditionally, so when they are implemented,\n"
1172 "%% this pgf file will use them.\n"
1174 "\\ifx\\du\\undefined\n"
1175 " \\newlength{\\du}\n"
1176 "\\fi\n"
1177 "\\setlength{\\du}{15\\unitlength}\n"
1178 "\\begin{tikzpicture}\n",
1179 diafilename,
1180 VERSION,
1181 ctime(&time_now),
1182 name);
1184 /* fprintf(renderer->file,"\\pspicture(%s,%s)(%s,%s)\n",
1185 pgf_dtostr(el_buf,extent->left * data->paper.scaling),
1186 pgf_dtostr(eb_buf,-extent->bottom * data->paper.scaling),
1187 pgf_dtostr(er_buf,extent->right * data->paper.scaling),
1188 pgf_dtostr(et_buf,-extent->top * data->paper.scaling) );
1190 fprintf(renderer->file,"\\pgftransformxscale{%s}\n"
1191 "\\pgftransformyscale{%s}\n",
1192 pgf_dtostr(scale1_buf,data->paper.scaling),
1193 pgf_dtostr(scale2_buf,-data->paper.scaling) );
1195 initial_color.red=0.;
1196 initial_color.green=0.;
1197 initial_color.blue=0.;
1198 set_line_color(renderer,&initial_color);
1200 initial_color.red=1.;
1201 initial_color.green=1.;
1202 initial_color.blue=1.;
1203 set_fill_color(renderer,&initial_color);
1205 data_render(data, DIA_RENDERER(renderer), NULL, NULL, NULL);
1207 g_object_unref(renderer);
1210 static const gchar *extensions[] = { "tex", NULL };
1211 DiaExportFilter pgf_export_filter = {
1212 N_("LaTeX PGF macros"),
1213 extensions,
1214 export_pgf