Date: 2026-07-30T21:14:22+00:00

Actual source code: tikz.c

      1: /*
      2:     Defines the operations for the TikZ PetscDraw implementation.
      3: */

      5: #include <petsc/private/drawimpl.h>

      7: typedef struct {
      8:   char     *filename;
      9:   FILE     *fd;
     10:   PetscBool written; /* something has been written to the current frame */
     11: } PetscDraw_TikZ;

     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"

     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"

     37: #define TikZ_END_FRAME \
     38:   "\\end{tikzpicture}\n\
     39: \\end{center}\n\
     40: \\end{changemargin}\n\
     41: \\end{frame}\n"

     43: #define TikZ_END_DOCUMENT "\\end{document}\n"

     45: static PetscErrorCode PetscDrawDestroy_TikZ(PetscDraw draw)
     46: {
     47:   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;

     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: }

     58: static const char *TikZColors[] = {"white", "black", "red", "green", "cyan", "blue", "magenta", NULL, NULL, "orange", "violet", "brown", "pink", NULL, "yellow", NULL};

     60: static inline const char *TikZColorMap(int cl)
     61: {
     62:   return (cl < 16) ? (TikZColors[cl] ? TikZColors[cl] : "black") : "black";
     63: }

     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)))

     71: static PetscErrorCode PetscDrawClear_TikZ(PetscDraw draw)
     72: {
     73:   PetscDraw_TikZ *win = (PetscDraw_TikZ *)draw->data;
     74:   PetscBool       written;

     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: }

     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;

     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: }

     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;

    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: }

    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;

    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: }

    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;

    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: }

    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;

    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: }

    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;

    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: }

    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;

    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));

    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: }

    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: }

    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};

    183: PETSC_EXTERN PetscErrorCode PetscDrawCreate_TikZ(PetscDraw draw)
    184: {
    185:   PetscDraw_TikZ *win;

    187:   PetscFunctionBegin;
    188:   draw->ops[0] = DvOps;
    189:   PetscCall(PetscNew(&win));

    191:   draw->data = (void *)win;

    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));

    204:   win->written = PETSC_FALSE;
    205:   PetscFunctionReturn(PETSC_SUCCESS);
    206: }