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 { 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 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 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 PetscCall(MPIU_Allreduce(&win->written, &written, 1, MPIU_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 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 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 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 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 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 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 - 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 */ 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 * len; 169 if (h) *h = .07; 170 PetscFunctionReturn(PETSC_SUCCESS); 171 } 172 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 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