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
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
48 -Image exporting function
49 -Implement PGF basic layer throughout
50 -Implement all the Arrow styles
64 #include <glib/gprintf.h>
67 #include "render_pgf.h"
69 #include "diagramdata.h"
70 #include "dia_image.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) \
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
,
93 static void draw_polyline(DiaRenderer
*self
,
94 Point
*points
, int num_points
,
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
,
102 static void fill_polygon(DiaRenderer
*self
,
103 Point
*points
, int num_points
,
105 static void draw_rect(DiaRenderer
*self
,
106 Point
*ul_corner
, Point
*lr_corner
,
108 static void fill_rect(DiaRenderer
*self
,
109 Point
*ul_corner
, Point
*lr_corner
,
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
,
119 real width
, real height
,
120 real angle1
, real angle2
,
122 static void fill_arc(DiaRenderer
*self
,
124 real width
, real height
,
125 real angle1
, real angle2
,
127 static void draw_ellipse(DiaRenderer
*self
,
129 real width
, real height
,
131 static void fill_ellipse(DiaRenderer
*self
,
133 real width
, real height
,
135 static void draw_bezier(DiaRenderer
*self
,
139 static void fill_bezier(DiaRenderer
*self
,
140 BezPoint
*points
, /* Last point must be same as first point */
143 static void draw_string(DiaRenderer
*self
,
145 Point
*pos
, Alignment alignment
,
147 static void draw_image(DiaRenderer
*self
,
149 real width
, real height
,
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
;
196 pgf_renderer_get_type (void)
198 static GType object_type
= 0;
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
),
215 object_type
= g_type_register_static (DIA_TYPE_RENDERER
,
224 pgf_renderer_finalize (GObject
*object
)
226 G_OBJECT_CLASS (parent_class
)->finalize (object
);
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
;
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");
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");
324 begin_render(DiaRenderer
*self
)
329 end_render(DiaRenderer
*self
)
331 PgfRenderer
*renderer
= PGF_RENDERER(self
);
333 fprintf(renderer
->file
,"\\end{tikzpicture}\n");
334 fclose(renderer
->file
);
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
) );
349 set_linecaps(DiaRenderer
*self
, LineCaps mode
)
351 PgfRenderer
*renderer
= PGF_RENDERER(self
);
355 fprintf(renderer
->file
, "\\pgfsetbuttcap\n");
358 fprintf(renderer
->file
, "\\pgfsetroundcap\n");
360 case LINECAPS_PROJECTING
:
361 fprintf(renderer
->file
, "\\pgfsetrectcap\n");
364 fprintf(renderer
->file
, "\\pgfsetbuttcap\n");
370 set_linejoin(DiaRenderer
*self
, LineJoin mode
)
372 PgfRenderer
*renderer
= PGF_RENDERER(self
);
377 fprintf(renderer
->file
, "\\pgfsetmiterjoin\n");
380 fprintf(renderer
->file
, "\\pgfsetroundjoin\n");
383 fprintf(renderer
->file
, "\\pgfsetbeveljoin\n");
386 fprintf(renderer
->file
, "\\pgfsetmiterjoin\n");
392 set_linestyle(DiaRenderer
*self
, LineStyle mode
)
394 PgfRenderer
*renderer
= PGF_RENDERER(self
);
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
;
403 case LINESTYLE_SOLID
:
404 fprintf(renderer
->file
, "\\pgfsetdash{}{0pt}\n");
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",
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",
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",
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
);
444 set_dashlength(DiaRenderer
*self
, real length
)
445 { /* dot = 20% of len */
446 PgfRenderer
*renderer
= PGF_RENDERER(self
);
451 renderer
->dash_length
= length
;
452 renderer
->dot_length
= length
*0.2;
454 set_linestyle(self
, renderer
->saved_line_style
);
458 set_fillstyle(DiaRenderer
*self
, FillStyle mode
)
461 case FILLSTYLE_SOLID
:
464 message_error("pgf_renderer: Unsupported fill mode specified!\n");
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");
478 draw_line(DiaRenderer
*self
,
479 Point
*start
, Point
*end
,
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
) );
498 draw_polyline(DiaRenderer
*self
,
499 Point
*points
, int num_points
,
502 PgfRenderer
*renderer
= PGF_RENDERER(self
);
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}}",
534 draw_polyline(self
,points
,num_points
,color
);
535 fprintf(renderer
->file
, "}");
539 pgf_polygon(PgfRenderer
*renderer
,
540 Point
*points
, gint num_points
,
541 Color
*line_color
, gboolean filled
)
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");
565 draw_polygon(DiaRenderer
*self
,
566 Point
*points
, int num_points
,
569 PgfRenderer
*renderer
= PGF_RENDERER(self
);
571 pgf_polygon(renderer
,points
,num_points
,line_color
,FALSE
);
575 fill_polygon(DiaRenderer
*self
,
576 Point
*points
, int num_points
,
579 PgfRenderer
*renderer
= PGF_RENDERER(self
);
581 pgf_polygon(renderer
,points
,num_points
,line_color
,TRUE
);
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"),
611 draw_rect(DiaRenderer
*self
,
612 Point
*ul_corner
, Point
*lr_corner
,
615 PgfRenderer
*renderer
= PGF_RENDERER(self
);
617 pgf_rect(renderer
,ul_corner
,lr_corner
,color
,FALSE
);
621 fill_rect(DiaRenderer
*self
,
622 Point
*ul_corner
, Point
*lr_corner
,
625 PgfRenderer
*renderer
= PGF_RENDERER(self
);
627 pgf_rect(renderer
,ul_corner
,lr_corner
,color
,TRUE
);
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}}",
641 pgf_rect(renderer
,ul_corner
,lr_corner
,color
,FALSE
);
642 fprintf(renderer
->file
, "}");
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}}",
655 pgf_rect(renderer
,ul_corner
,lr_corner
,color
,TRUE
);
656 fprintf(renderer
->file
, "}");
661 pgf_arc(PgfRenderer
*renderer
,
663 real width
, real height
,
664 real angle1
, real angle2
,
665 Color
*color
,int filled
)
667 double radius1
,radius2
;
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
));
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",
701 fprintf(renderer
->file
,"\\pgfpatharc{%s}{%s}{%s\\du/%s\\du}\n",
702 angle1_buf
, angle2_buf
,
706 fprintf(renderer
->file
, "\\pgfusepath{fill}\n");
708 fprintf(renderer
->file
, "\\pgfusepath{stroke}\n");
712 draw_arc(DiaRenderer
*self
,
714 real width
, real height
,
715 real angle1
, real angle2
,
718 PgfRenderer
*renderer
= PGF_RENDERER(self
);
720 pgf_arc(renderer
,center
,width
,height
,angle1
,angle2
,color
,0);
724 fill_arc(DiaRenderer
*self
,
726 real width
, real height
,
727 real angle1
, real angle2
,
730 PgfRenderer
*renderer
= PGF_RENDERER(self
);
732 pgf_arc(renderer
,center
,width
,height
,angle1
,angle2
,color
,1);
736 pgf_ellipse(PgfRenderer
*renderer
,
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") );
763 draw_ellipse(DiaRenderer
*self
,
765 real width
, real height
,
768 PgfRenderer
*renderer
= PGF_RENDERER(self
);
770 pgf_ellipse(renderer
,center
,width
,height
,color
,FALSE
);
774 fill_ellipse(DiaRenderer
*self
,
776 real width
, real height
,
779 PgfRenderer
*renderer
= PGF_RENDERER(self
);
781 pgf_ellipse(renderer
,center
,width
,height
,color
,TRUE
);
785 pgf_bezier(PgfRenderer
*renderer
,
788 Color
*color
, gboolean filled
)
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
) {
811 g_warning("only first BezPoint can be a BEZ_MOVE_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
) );
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
) );
832 fprintf(renderer
->file
, "\\pgfusepath{fill}\n");
834 /* fill[fillstyle=solid,fillcolor=diafillcolor,linecolor=diafillcolor]}\n"); */
836 fprintf(renderer
->file
, "\\pgfusepath{stroke}\n");
840 draw_bezier(DiaRenderer
*self
,
842 int numpoints
, /* numpoints = 4+3*n, n=>0 */
845 PgfRenderer
*renderer
= PGF_RENDERER(self
);
847 pgf_bezier(renderer
,points
,numpoints
,color
,FALSE
);
853 fill_bezier(DiaRenderer
*self
,
854 BezPoint
*points
, /* Last point must be same as first point */
858 PgfRenderer
*renderer
= PGF_RENDERER(self
);
860 pgf_bezier(renderer
,points
,numpoints
,color
,TRUE
);
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
)
873 fprintf(renderer
->file
, "\\pgfsetarrowsstart{to}\n");
875 case ARROW_FILLED_TRIANGLE
:
876 fprintf(renderer
->file
, "\\pgfsetarrowsstart{latex}\n");
878 case ARROW_FILLED_CONCAVE
:
879 fprintf(renderer
->file
, "\\pgfsetarrowsstart{stealth}\n");
884 if (modified
& 2) start_arrow
->type
= ARROW_NONE
;
886 switch (end_arrow
->type
)
891 fprintf(renderer
->file
, "\\pgfsetarrowsend{to}\n");
893 case ARROW_FILLED_TRIANGLE
:
894 fprintf(renderer
->file
, "\\pgfsetarrowsend{latex}\n");
896 case ARROW_FILLED_CONCAVE
:
897 fprintf(renderer
->file
, "\\pgfsetarrowsend{stealth}\n");
902 if (modified
& 1) end_arrow
->type
= ARROW_NONE
;
904 return modified
; /* =0 if no native arrow is used */
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
)
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
);
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");
928 orig_draw_line_with_arrows(self
, start
, end
, line_width
, line_color
, &st_arrow
, &e_arrow
);
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
)
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
);
947 orig_draw_arc_with_arrows(self
, start
, end
, midpoint
, line_width
, color
, NULL
, NULL
);
949 fprintf(renderer
->file
, "}\n");
952 orig_draw_arc_with_arrows(self
, start
, end
, midpoint
, line_width
, color
, &st_arrow
, &e_arrow
);
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
)
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
);
970 orig_draw_polyline_with_arrows(self
, points
, num_points
, line_width
, color
, NULL
, NULL
);
972 fprintf(renderer
->file
, "}\n");
975 orig_draw_polyline_with_arrows(self
, points
, num_points
, line_width
, color
, &st_arrow
, &e_arrow
);
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
)
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
);
993 orig_draw_rounded_polyline_with_arrows(self
, points
, num_points
,
994 line_width
, color
, NULL
, NULL
, radius
);
996 fprintf(renderer
->file
, "}\n");
999 orig_draw_rounded_polyline_with_arrows(self
, points
, num_points
,
1000 line_width
, color
, &st_arrow
, &e_arrow
, radius
);
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
)
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
);
1018 orig_draw_bezier_with_arrows(self
, points
, num_points
, line_width
, color
, &st_arrow
, &e_arrow
);
1020 fprintf(renderer
->file
, "}\n");
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 ...
1041 tex_escape_string(const gchar
*src
)
1043 GString
*dest
= g_string_sized_new(g_utf8_strlen(src
, -1));
1046 if (!g_utf8_validate(src
, -1, NULL
)) {
1047 message_error(_("Not valid UTF8"));
1048 return g_strdup(src
);
1052 while (*p
!= '\0') {
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;
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
);
1074 g_string_free(dest
, FALSE
);
1079 draw_string(DiaRenderer
*self
,
1081 Point
*pos
, Alignment alignment
,
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
) {
1094 fprintf(renderer
->file
,"[anchor=west]");
1099 fprintf(renderer
->file
,"[anchor=east]");
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
),
1110 draw_image(DiaRenderer
*self
,
1112 real width
, real height
,
1115 PgfRenderer
*renderer
= PGF_RENDERER(self
);
1117 fprintf(renderer
->file
, "%% image rendering not supported");
1120 /* --- export filter interface --- */
1122 export_pgf(DiagramData
*data
, const gchar
*filename
,
1123 const gchar
*diafilename
, void* user_data
)
1125 PgfRenderer
*renderer
;
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");
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();
1164 "%% Graphic for TeX using PGF\n"
1166 "%% Creator: Dia v%s\n"
1167 "%% CreationDate: %s"
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"
1177 "\\setlength{\\du}{15\\unitlength}\n"
1178 "\\begin{tikzpicture}\n",
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"),