xref: /petsc/src/sys/classes/draw/impls/tikz/tikz.c (revision 58d68138c660dfb4e9f5b03334792cd4f2ffd7cc)
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 
45 static PetscErrorCode PetscDrawDestroy_TikZ(PetscDraw draw) {
46   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
47 
48   PetscFunctionBegin;
49   PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_END_FRAME));
50   PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_END_DOCUMENT));
51   PetscCall(PetscFClose(PetscObjectComm((PetscObject)draw), win->fd));
52   PetscCall(PetscFree(win->filename));
53   PetscCall(PetscFree(draw->data));
54   PetscFunctionReturn(0);
55 }
56 
57 static const char *TikZColors[] = {"white", "black", "red", "green", "cyan", "blue", "magenta", NULL, NULL, "orange", "violet", "brown", "pink", NULL, "yellow", NULL};
58 
59 static inline const char *TikZColorMap(int cl) {
60   return ((cl < 16) ? (TikZColors[cl] ? TikZColors[cl] : "black") : "black");
61 }
62 
63 /*
64      These macros transform from the users coordinates to the (0,0) -> (1,1) coordinate system
65 */
66 #define XTRANS(draw, x) (double)(((draw)->port_xl + (((x - (draw)->coor_xl) * ((draw)->port_xr - (draw)->port_xl)) / ((draw)->coor_xr - (draw)->coor_xl))))
67 #define YTRANS(draw, y) (double)(((draw)->port_yl + (((y - (draw)->coor_yl) * ((draw)->port_yr - (draw)->port_yl)) / ((draw)->coor_yr - (draw)->coor_yl))))
68 
69 static PetscErrorCode PetscDrawClear_TikZ(PetscDraw draw) {
70   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
71   PetscBool       written;
72 
73   PetscFunctionBegin;
74   /* often PETSc generates unneeded clears, we want avoid creating empy pictures for them */
75   PetscCallMPI(MPI_Allreduce(&win->written, &written, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)(draw))));
76   if (!written) PetscFunctionReturn(0);
77   PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_END_FRAME));
78   PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_BEGIN_FRAME));
79   win->written = PETSC_FALSE;
80   PetscFunctionReturn(0);
81 }
82 
83 static PetscErrorCode PetscDrawLine_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int cl) {
84   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
85 
86   PetscFunctionBegin;
87   win->written = PETSC_TRUE;
88   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)));
89   PetscFunctionReturn(0);
90 }
91 
92 static PetscErrorCode PetscDrawRectangle_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, PetscReal xr, PetscReal yr, int c1, int c2, int c3, int c4) {
93   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
94 
95   PetscFunctionBegin;
96   win->written = PETSC_TRUE;
97   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)));
98   PetscFunctionReturn(0);
99 }
100 
101 static PetscErrorCode PetscDrawTriangle_TikZ(PetscDraw draw, PetscReal x1, PetscReal y1, PetscReal x2, PetscReal y2, PetscReal x3, PetscReal y3, int c1, int c2, int c3) {
102   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
103 
104   PetscFunctionBegin;
105   win->written = PETSC_TRUE;
106   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)));
107   PetscFunctionReturn(0);
108 }
109 
110 static PetscErrorCode PetscDrawEllipse_TikZ(PetscDraw draw, PetscReal x, PetscReal y, PetscReal a, PetscReal b, int c) {
111   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
112   PetscReal       rx, ry;
113 
114   PetscFunctionBegin;
115   win->written = PETSC_TRUE;
116   rx           = a / 2 * (draw->port_xr - draw->port_xl) / (draw->coor_xr - draw->coor_xl);
117   ry           = b / 2 * (draw->port_yr - draw->port_yl) / (draw->coor_yr - draw->coor_yl);
118   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));
119   PetscFunctionReturn(0);
120 }
121 
122 static PetscErrorCode PetscDrawString_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, int cl, const char text[]) {
123   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
124 
125   PetscFunctionBegin;
126   win->written = PETSC_TRUE;
127   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));
128   PetscFunctionReturn(0);
129 }
130 
131 static PetscErrorCode PetscDrawStringVertical_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, int cl, const char text[]) {
132   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
133   size_t          len;
134   PetscReal       width;
135 
136   PetscFunctionBegin;
137   win->written = PETSC_TRUE;
138   PetscCall(PetscStrlen(text, &len));
139   PetscCall(PetscDrawStringGetSize(draw, &width, NULL));
140   yl = yl - len * width * (draw->coor_yr - draw->coor_yl) / (draw->coor_xr - draw->coor_xl);
141   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));
142   PetscFunctionReturn(0);
143 }
144 
145 /*
146     Does not handle multiline strings correctly
147 */
148 static PetscErrorCode PetscDrawStringBoxed_TikZ(PetscDraw draw, PetscReal xl, PetscReal yl, int cl, int ct, const char text[], PetscReal *w, PetscReal *h) {
149   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
150   size_t          len;
151 
152   PetscFunctionBegin;
153   win->written = PETSC_TRUE;
154   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));
155 
156   /* make up totally bogus height and width of box */
157   PetscCall(PetscStrlen(text, &len));
158   if (w) *w = .07 * len;
159   if (h) *h = .07;
160   PetscFunctionReturn(0);
161 }
162 
163 static PetscErrorCode PetscDrawStringGetSize_TikZ(PetscDraw draw, PetscReal *x, PetscReal *y) {
164   PetscFunctionBegin;
165   if (x) *x = .014 * (draw->coor_xr - draw->coor_xl) / ((draw->port_xr - draw->port_xl));
166   if (y) *y = .05 * (draw->coor_yr - draw->coor_yl) / ((draw->port_yr - draw->port_yl));
167   PetscFunctionReturn(0);
168 }
169 
170 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};
171 
172 PETSC_EXTERN PetscErrorCode PetscDrawCreate_TikZ(PetscDraw draw) {
173   PetscDraw_TikZ *win;
174 
175   PetscFunctionBegin;
176   PetscCall(PetscMemcpy(draw->ops, &DvOps, sizeof(DvOps)));
177   PetscCall(PetscNew(&win));
178   PetscCall(PetscLogObjectMemory((PetscObject)draw, sizeof(PetscDraw_TikZ)));
179 
180   draw->data = (void *)win;
181 
182   if (draw->title) {
183     PetscCall(PetscStrallocpy(draw->title, &win->filename));
184   } else {
185     const char *fname;
186     PetscCall(PetscObjectGetName((PetscObject)draw, &fname));
187     PetscCall(PetscStrallocpy(fname, &win->filename));
188   }
189   PetscCall(PetscFOpen(PetscObjectComm((PetscObject)draw), win->filename, "w", &win->fd));
190   PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_BEGIN_DOCUMENT));
191   PetscCall(PetscFPrintf(PetscObjectComm((PetscObject)draw), win->fd, TikZ_BEGIN_FRAME));
192 
193   win->written = PETSC_FALSE;
194   PetscFunctionReturn(0);
195 }
196