1 /*
2 Defines the operations for the TikZ PetscDraw implementation.
3 */
4
5 #include <petsc/private/drawimpl.h> /*I "petscsys.h" I*/
6
7 typedef struct {
8 char *filename;
9 FILE *fd;
10 PetscBool written; /* something has been written to the current frame */
11 } PetscDraw_TikZ;
12
13 #define TikZ_BEGIN_DOCUMENT \
14 "\\documentclass{beamer}\n\n\
15 \\usepackage{tikz}\n\
16 \\usepackage{pgflibraryshapes}\n\
17 \\usetikzlibrary{backgrounds}\n\
18 \\usetikzlibrary{arrows}\n\
19 \\newenvironment{changemargin}[2]{%%\n\
20 \\begin{list}{}{%%\n\
21 \\setlength{\\topsep}{0pt}%%\n\
22 \\setlength{\\leftmargin}{#1}%%\n\
23 \\setlength{\\rightmargin}{#2}%%\n\
24 \\setlength{\\listparindent}{\\parindent}%%\n\
25 \\setlength{\\itemindent}{\\parindent}%%\n\
26 \\setlength{\\parsep}{\\parskip}%%\n\
27 }%%\n\
28 \\item[]}{\\end{list}}\n\n\
29 \\begin{document}\n"
30
31 #define TikZ_BEGIN_FRAME \
32 "\\begin{frame}{}\n\
33 \\begin{changemargin}{-1cm}{0cm}\n\
34 \\begin{center}\n\
35 \\begin{tikzpicture}[scale = 10.00,font=\\fontsize{8}{8}\\selectfont]\n"
36
37 #define TikZ_END_FRAME \
38 "\\end{tikzpicture}\n\
39 \\end{center}\n\
40 \\end{changemargin}\n\
41 \\end{frame}\n"
42
43 #define TikZ_END_DOCUMENT "\\end{document}\n"
44
PetscDrawDestroy_TikZ(PetscDraw draw)45 static PetscErrorCode PetscDrawDestroy_TikZ(PetscDraw draw)
46 {
47 PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
48
49 PetscFunctionBegin;
50 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_END_FRAME));
51 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_END_DOCUMENT));
52 PetscCall(PetscFClose(PetscObjectComm((PetscObject)draw), win->fd));
53 PetscCall(PetscFree(win->filename));
54 PetscCall(PetscFree(draw->data));
55 PetscFunctionReturn(PETSC_SUCCESS);
56 }
57
58 static const char *TikZColors[] = {"white", "black", "red", "green", "cyan", "blue", "magenta", NULL, NULL, "orange", "violet", "brown", "pink", NULL, "yellow", NULL};
59
TikZColorMap(int cl)60 static inline const char *TikZColorMap(int cl)
61 {
62 return (cl < 16) ? (TikZColors[cl] ? TikZColors[cl] : "black") : "black";
63 }
64
65 /*
66 These macros transform from the users coordinates to the (0,0) -> (1,1) coordinate system
67 */
68 #define XTRANS(draw, x) (double)((draw)->port_xl + (((x - (draw)->coor_xl) * ((draw)->port_xr - (draw)->port_xl)) / ((draw)->coor_xr - (draw)->coor_xl)))
69 #define YTRANS(draw, y) (double)((draw)->port_yl + (((y - (draw)->coor_yl) * ((draw)->port_yr - (draw)->port_yl)) / ((draw)->coor_yr - (draw)->coor_yl)))
70
PetscDrawClear_TikZ(PetscDraw draw)71 static PetscErrorCode PetscDrawClear_TikZ(PetscDraw draw)
72 {
73 PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
74 PetscBool written;
75
76 PetscFunctionBegin;
77 /* often PETSc generates unneeded clears, we want avoid creating empty pictures for them */
78 PetscCallMPI(MPIU_Allreduce(&win->written, &written, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)draw)));
79 if (!written) PetscFunctionReturn(PETSC_SUCCESS);
80 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_END_FRAME));
81 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_BEGIN_FRAME));
82 win->written = PETSC_FALSE;
83 PetscFunctionReturn(PETSC_SUCCESS);
84 }
85
PetscDrawLine_TikZ(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int cl)86 static PetscErrorCode PetscDrawLine_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int cl)
87 {
88 PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
89
90 PetscFunctionBegin;
91 win->written = PETSC_TRUE;
92 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, "\\draw [%s] (%g,%g) --(%g,%g);\n", TikZColorMap(cl), XTRANS(draw, xl), YTRANS(draw, yl), XTRANS(draw, xr), YTRANS(draw, yr)));
93 PetscFunctionReturn(PETSC_SUCCESS);
94 }
95
PetscDrawRectangle_TikZ(PetscDraw draw,PetscReal xl,PetscReal yl,PetscReal xr,PetscReal yr,int c1,int c2,int c3,int c4)96 static PetscErrorCode PetscDrawRectangle_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int c1, int c2, int c3, int c4)
97 {
98 PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
99
100 PetscFunctionBegin;
101 win->written = PETSC_TRUE;
102 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, "\\fill [bottom color=%s,top color=%s] (%g,%g) rectangle (%g,%g);\n", TikZColorMap(c1), TikZColorMap(c4), XTRANS(draw, xl), YTRANS(draw, yl), XTRANS(draw, xr), YTRANS(draw, yr)));
103 PetscFunctionReturn(PETSC_SUCCESS);
104 }
105
PetscDrawTriangle_TikZ(PetscDraw draw,PetscReal x1,PetscReal y1,PetscReal x2,PetscReal y2,PetscReal x3,PetscReal y3,int c1,int c2,int c3)106 static PetscErrorCode PetscDrawTriangle_TikZ(PetscDraw draw, PetscReal x1, PetscReal y1, PetscReal x2, PetscReal y2, PetscReal x3, PetscReal y3, int c1, int c2, int c3)
107 {
108 PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
109
110 PetscFunctionBegin;
111 win->written = PETSC_TRUE;
112 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, "\\fill [color=%s] (%g,%g) -- (%g,%g) -- (%g,%g) -- cycle;\n", TikZColorMap(c1), XTRANS(draw, x1), YTRANS(draw, y1), XTRANS(draw, x2), YTRANS(draw, y2), XTRANS(draw, x3), YTRANS(draw, y3)));
113 PetscFunctionReturn(PETSC_SUCCESS);
114 }
115
PetscDrawEllipse_TikZ(PetscDraw draw,PetscReal x,PetscReal y,PetscReal a,PetscReal b,int c)116 static PetscErrorCode PetscDrawEllipse_TikZ(PetscDraw draw, PetscReal x, PetscReal y, PetscReal a, PetscReal b, int c)
117 {
118 PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
119 PetscReal rx, ry;
120
121 PetscFunctionBegin;
122 win->written = PETSC_TRUE;
123 rx = a / 2 * (draw->port_xr - draw->port_xl) / (draw->coor_xr - draw->coor_xl);
124 ry = b / 2 * (draw->port_yr - draw->port_yl) / (draw->coor_yr - draw->coor_yl);
125 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, "\\fill [color=%s] (%g,%g) circle [x radius=%g,y radius=%g];\n", TikZColorMap(c), XTRANS(draw, x), YTRANS(draw, y), (double)rx, (double)ry));
126 PetscFunctionReturn(PETSC_SUCCESS);
127 }
128
PetscDrawString_TikZ(PetscDraw draw,PetscReal xl,PetscReal yl,int cl,const char text[])129 static PetscErrorCode PetscDrawString_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, int cl, const char text[])
130 {
131 PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
132
133 PetscFunctionBegin;
134 win->written = PETSC_TRUE;
135 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, "\\node [above right, %s] at (%g,%g) {%s};\n", TikZColorMap(cl), XTRANS(draw, xl), YTRANS(draw, yl), text));
136 PetscFunctionReturn(PETSC_SUCCESS);
137 }
138
PetscDrawStringVertical_TikZ(PetscDraw draw,PetscReal xl,PetscReal yl,int cl,const char text[])139 static PetscErrorCode PetscDrawStringVertical_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, int cl, const char text[])
140 {
141 PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
142 size_t len;
143 PetscReal width;
144
145 PetscFunctionBegin;
146 win->written = PETSC_TRUE;
147 PetscCall(PetscStrlen(text, &len));
148 PetscCall(PetscDrawStringGetSize(draw, &width, NULL));
149 yl = yl - ((PetscReal)len) * width * (draw->coor_yr - draw->coor_yl) / (draw->coor_xr - draw->coor_xl);
150 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, "\\node [rotate=90, %s] at (%g,%g) {%s};\n", TikZColorMap(cl), XTRANS(draw, xl), YTRANS(draw, yl), text));
151 PetscFunctionReturn(PETSC_SUCCESS);
152 }
153
154 /*
155 Does not handle multiline strings correctly
156 */
PetscDrawStringBoxed_TikZ(PetscDraw draw,PetscReal xl,PetscReal yl,int cl,int ct,const char text[],PetscReal * w,PetscReal * h)157 static PetscErrorCode PetscDrawStringBoxed_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, int cl, int ct, const char text[], PetscReal *w, PetscReal *h)
158 {
159 PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
160 size_t len;
161
162 PetscFunctionBegin;
163 win->written = PETSC_TRUE;
164 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, "\\draw (%g,%g) node [rectangle, draw, align=center, inner sep=1ex] {%s};\n", XTRANS(draw, xl), YTRANS(draw, yl), text));
165
166 /* make up totally bogus height and width of box */
167 PetscCall(PetscStrlen(text, &len));
168 if (w) *w = .07 * (PetscReal)len;
169 if (h) *h = .07;
170 PetscFunctionReturn(PETSC_SUCCESS);
171 }
172
PetscDrawStringGetSize_TikZ(PetscDraw draw,PetscReal * x,PetscReal * y)173 static PetscErrorCode PetscDrawStringGetSize_TikZ(PetscDraw draw, PetscReal *x, PetscReal *y)
174 {
175 PetscFunctionBegin;
176 if (x) *x = .014 * (draw->coor_xr - draw->coor_xl) / (draw->port_xr - draw->port_xl);
177 if (y) *y = .05 * (draw->coor_yr - draw->coor_yl) / (draw->port_yr - draw->port_yl);
178 PetscFunctionReturn(PETSC_SUCCESS);
179 }
180
181 static struct _PetscDrawOps DvOps = {NULL, NULL, PetscDrawLine_TikZ, NULL, NULL, NULL, NULL, PetscDrawString_TikZ, PetscDrawStringVertical_TikZ, NULL, PetscDrawStringGetSize_TikZ, NULL, PetscDrawClear_TikZ, PetscDrawRectangle_TikZ, PetscDrawTriangle_TikZ, PetscDrawEllipse_TikZ, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, PetscDrawDestroy_TikZ, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, PetscDrawStringBoxed_TikZ, NULL};
182
PetscDrawCreate_TikZ(PetscDraw draw)183 PETSC_EXTERN PetscErrorCode PetscDrawCreate_TikZ(PetscDraw draw)
184 {
185 PetscDraw_TikZ *win;
186
187 PetscFunctionBegin;
188 draw->ops[0] = DvOps;
189 PetscCall(PetscNew(&win));
190
191 draw->data = (void *)win;
192
193 if (draw->title) {
194 PetscCall(PetscStrallocpy(draw->title, &win->filename));
195 } else {
196 const char *fname;
197 PetscCall(PetscObjectGetName((PetscObject)draw, &fname));
198 PetscCall(PetscStrallocpy(fname, &win->filename));
199 }
200 PetscCall(PetscFOpen(PetscObjectComm((PetscObject)draw), win->filename, "w", &win->fd));
201 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_BEGIN_DOCUMENT));
202 PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_BEGIN_FRAME));
203
204 win->written = PETSC_FALSE;
205 PetscFunctionReturn(PETSC_SUCCESS);
206 }
207