Fix string handling for gcc 7
[gromacs.git] / src / gromacs / gmxana / gmx_xpm2ps.cpp
blobbe80038239315c36d666740d3598a118d8cd2edf
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 #include "gmxpre.h"
39 #include <cassert>
40 #include <cmath>
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
45 #include <algorithm>
46 #include <string>
48 #include "gromacs/commandline/pargs.h"
49 #include "gromacs/commandline/viewit.h"
50 #include "gromacs/fileio/matio.h"
51 #include "gromacs/fileio/readinp.h"
52 #include "gromacs/fileio/trxio.h"
53 #include "gromacs/fileio/warninp.h"
54 #include "gromacs/fileio/writeps.h"
55 #include "gromacs/gmxana/gmx_ana.h"
56 #include "gromacs/utility/arraysize.h"
57 #include "gromacs/utility/cstringutil.h"
58 #include "gromacs/utility/fatalerror.h"
59 #include "gromacs/utility/futil.h"
60 #include "gromacs/utility/gmxassert.h"
61 #include "gromacs/utility/smalloc.h"
62 #include "gromacs/utility/stringutil.h"
64 #define FUDGE 1.2
65 #define DDD 2
67 typedef struct {
68 real major;
69 real minor;
70 real offset;
71 gmx_bool first;
72 int lineatzero;
73 real majorticklen;
74 real minorticklen;
75 char label[STRLEN];
76 real fontsize;
77 char font[STRLEN];
78 real tickfontsize;
79 char tickfont[STRLEN];
80 } t_axisdef;
82 typedef struct {
83 int bw;
84 real linewidth;
85 real xoffs, yoffs;
86 gmx_bool bTitle;
87 gmx_bool bTitleOnce;
88 gmx_bool bYonce;
89 real titfontsize;
90 char titfont[STRLEN];
91 gmx_bool legend;
92 real legfontsize;
93 char legfont[STRLEN];
94 char leglabel[STRLEN];
95 char leg2label[STRLEN];
96 real xboxsize;
97 real yboxsize;
98 real boxspacing;
99 real boxlinewidth;
100 real ticklinewidth;
101 real zerolinewidth;
102 t_axisdef X, Y;
103 } t_psrec;
105 /* MUST correspond to char *legend[] in main() */
106 enum {
107 elSel, elBoth, elFirst, elSecond, elNone, elNR
110 /* MUST correspond to char *combine[] in main() */
111 enum {
112 ecSel, ecHalves, ecAdd, ecSub, ecMult, ecDiv, ecNR
115 void get_params(const char *mpin, const char *mpout, t_psrec *psr)
117 static const char *gmx_bools[BOOL_NR+1] = { "no", "yes", NULL };
118 /* this must correspond to t_rgb *linecolors[] below */
119 static const char *colors[] = { "none", "black", "white", NULL };
120 warninp_t wi;
121 t_inpfile *inp;
122 const char *tmp;
123 int ninp = 0;
125 wi = init_warning(FALSE, 0);
127 if (mpin != NULL)
129 inp = read_inpfile(mpin, &ninp, wi);
131 else
133 inp = NULL;
135 ETYPE("black&white", psr->bw, gmx_bools);
136 RTYPE("linewidth", psr->linewidth, 1.0);
137 STYPE("titlefont", psr->titfont, "Helvetica");
138 RTYPE("titlefontsize", psr->titfontsize, 20.0);
139 ETYPE("legend", psr->legend, gmx_bools);
140 STYPE("legendfont", psr->legfont, psr->titfont);
141 STYPE("legendlabel", psr->leglabel, "");
142 STYPE("legend2label", psr->leg2label, psr->leglabel);
143 RTYPE("legendfontsize", psr->legfontsize, 14.0);
144 RTYPE("xbox", psr->xboxsize, 0.0);
145 RTYPE("ybox", psr->yboxsize, 0.0);
146 RTYPE("matrixspacing", psr->boxspacing, 20.0);
147 RTYPE("xoffset", psr->xoffs, 0.0);
148 RTYPE("yoffset", psr->yoffs, psr->xoffs);
149 RTYPE("boxlinewidth", psr->boxlinewidth, psr->linewidth);
150 RTYPE("ticklinewidth", psr->ticklinewidth, psr->linewidth);
151 RTYPE("zerolinewidth", psr->zerolinewidth, psr->ticklinewidth);
152 ETYPE("x-lineat0value", psr->X.lineatzero, colors);
153 RTYPE("x-major", psr->X.major, 1);
154 RTYPE("x-minor", psr->X.minor, 1);
155 RTYPE("x-firstmajor", psr->X.offset, 0.0);
156 ETYPE("x-majorat0", psr->X.first, gmx_bools);
157 RTYPE("x-majorticklen", psr->X.majorticklen, 8.0);
158 RTYPE("x-minorticklen", psr->X.minorticklen, 4.0);
159 STYPE("x-label", psr->X.label, "");
160 RTYPE("x-fontsize", psr->X.fontsize, 16.0);
161 STYPE("x-font", psr->X.font, psr->titfont);
162 RTYPE("x-tickfontsize", psr->X.tickfontsize, 10.0);
163 STYPE("x-tickfont", psr->X.tickfont, psr->X.font);
164 ETYPE("y-lineat0value", psr->Y.lineatzero, colors);
165 RTYPE("y-major", psr->Y.major, psr->X.major);
166 RTYPE("y-minor", psr->Y.minor, psr->X.minor);
167 RTYPE("y-firstmajor", psr->Y.offset, psr->X.offset);
168 ETYPE("y-majorat0", psr->Y.first, gmx_bools);
169 RTYPE("y-majorticklen", psr->Y.majorticklen, psr->X.majorticklen);
170 RTYPE("y-minorticklen", psr->Y.minorticklen, psr->X.minorticklen);
171 STYPE("y-label", psr->Y.label, psr->X.label);
172 RTYPE("y-fontsize", psr->Y.fontsize, psr->X.fontsize);
173 STYPE("y-font", psr->Y.font, psr->X.font);
174 RTYPE("y-tickfontsize", psr->Y.tickfontsize, psr->X.tickfontsize);
175 STYPE("y-tickfont", psr->Y.tickfont, psr->Y.font);
177 check_warning_error(wi, FARGS);
179 if (mpout != NULL)
181 write_inpfile(mpout, ninp, inp, TRUE, wi);
184 done_warning(wi, FARGS);
187 t_rgb black = { 0, 0, 0 };
188 t_rgb white = { 1, 1, 1 };
189 t_rgb red = { 1, 0, 0 };
190 t_rgb blue = { 0, 0, 1 };
191 #define BLACK (&black)
192 /* this must correspond to *colors[] in get_params */
193 t_rgb *linecolors[] = { NULL, &black, &white, NULL };
195 gmx_bool diff_maps(int nmap1, t_mapping *map1, int nmap2, t_mapping *map2)
197 int i;
198 gmx_bool bDiff, bColDiff = FALSE;
200 if (nmap1 != nmap2)
202 bDiff = TRUE;
204 else
206 bDiff = FALSE;
207 for (i = 0; i < nmap1; i++)
209 if (!matelmt_cmp(map1[i].code, map2[i].code))
211 bDiff = TRUE;
213 if (std::strcmp(map1[i].desc, map2[i].desc) != 0)
215 bDiff = TRUE;
217 if ((map1[i].rgb.r != map2[i].rgb.r) ||
218 (map1[i].rgb.g != map2[i].rgb.g) ||
219 (map1[i].rgb.b != map2[i].rgb.b))
221 bColDiff = TRUE;
224 if (!bDiff && bColDiff)
226 fprintf(stderr, "Warning: two colormaps differ only in RGB value, using one colormap.\n");
230 return bDiff;
233 void leg_discrete(t_psdata ps, real x0, real y0, char *label,
234 real fontsize, char *font, int nmap, t_mapping map[])
236 int i;
237 real yhh;
238 real boxhh;
240 boxhh = fontsize+DDD;
241 /* LANDSCAPE */
242 ps_rgb(ps, BLACK);
243 ps_strfont(ps, font, fontsize);
244 yhh = y0+fontsize+3*DDD;
245 if (std::strlen(label) > 0)
247 ps_ctext(ps, x0, yhh, label, eXLeft);
249 ps_moveto(ps, x0, y0);
250 for (i = 0; (i < nmap); i++)
252 ps_setorigin(ps);
253 ps_rgb(ps, &(map[i].rgb));
254 ps_fillbox(ps, DDD, DDD, DDD+fontsize, boxhh-DDD);
255 ps_rgb(ps, BLACK);
256 ps_box(ps, DDD, DDD, DDD+fontsize, boxhh-DDD);
257 ps_ctext(ps, boxhh+2*DDD, fontsize/3, map[i].desc, eXLeft);
258 ps_unsetorigin(ps);
259 ps_moverel(ps, DDD, -fontsize/3);
263 void leg_continuous(t_psdata ps, real x0, real x, real y0, char *label,
264 real fontsize, char *font,
265 int nmap, t_mapping map[],
266 int mapoffset)
268 int i;
269 real xx0;
270 real yhh, boxxh, boxyh;
272 boxyh = fontsize;
273 if (x < 8*fontsize)
275 x = 8*fontsize;
277 boxxh = x/(nmap-mapoffset);
278 if (boxxh > fontsize)
280 boxxh = fontsize;
283 GMX_RELEASE_ASSERT(map != NULL, "NULL map array provided to leg_continuous()");
285 /* LANDSCAPE */
286 xx0 = x0-((nmap-mapoffset)*boxxh)/2.0;
288 for (i = 0; (i < nmap-mapoffset); i++)
290 ps_rgb(ps, &(map[i+mapoffset].rgb));
291 ps_fillbox(ps, xx0+i*boxxh, y0, xx0+(i+1)*boxxh, y0+boxyh);
293 ps_strfont(ps, font, fontsize);
294 ps_rgb(ps, BLACK);
295 ps_box(ps, xx0, y0, xx0+(nmap-mapoffset)*boxxh, y0+boxyh);
297 yhh = y0+boxyh+3*DDD;
298 ps_ctext(ps, xx0+boxxh/2, yhh, map[0].desc, eXCenter);
299 if (std::strlen(label) > 0)
301 ps_ctext(ps, x0, yhh, label, eXCenter);
303 ps_ctext(ps, xx0+((nmap-mapoffset)*boxxh)
304 - boxxh/2, yhh, map[nmap-1].desc, eXCenter);
307 void leg_bicontinuous(t_psdata ps, real x0, real x, real y0, char *label1,
308 char *label2, real fontsize, char *font,
309 int nmap1, t_mapping map1[], int nmap2, t_mapping map2[])
311 real xx1, xx2, x1, x2;
313 x1 = x/(nmap1+nmap2)*nmap1; /* width of legend 1 */
314 x2 = x/(nmap1+nmap2)*nmap2; /* width of legend 2 */
315 xx1 = x0-(x2/2.0)-fontsize; /* center of legend 1 */
316 xx2 = x0+(x1/2.0)+fontsize; /* center of legend 2 */
317 x1 -= fontsize/2; /* adjust width */
318 x2 -= fontsize/2; /* adjust width */
319 leg_continuous(ps, xx1, x1, y0, label1, fontsize, font, nmap1, map1, 0);
320 leg_continuous(ps, xx2, x2, y0, label2, fontsize, font, nmap2, map2, 0);
323 static real box_height(t_matrix *mat, t_psrec *psr)
325 return mat->ny*psr->yboxsize;
328 static real box_dh(t_psrec *psr)
330 return psr->boxspacing;
333 #define IS_ONCE (i == nmat-1)
334 static real box_dh_top(gmx_bool bOnce, t_psrec *psr)
336 real dh;
338 if (psr->bTitle || (psr->bTitleOnce && bOnce) )
340 dh = 2*psr->titfontsize;
342 else
344 dh = 0;
347 return dh;
350 static gmx_bool box_do_all_x_maj_ticks(t_psrec *psr)
352 return (psr->boxspacing > (1.5*psr->X.majorticklen));
355 static gmx_bool box_do_all_x_min_ticks(t_psrec *psr)
357 return (psr->boxspacing > (1.5*psr->X.minorticklen));
360 static void draw_boxes(t_psdata ps, real x0, real y0, real w,
361 int nmat, t_matrix mat[], t_psrec *psr)
363 char buf[128];
364 char *mylab;
365 real xxx;
366 char **xtick, **ytick;
367 real xx, yy, dy, xx00, yy00, offset_x, offset_y;
368 int i, j, x, y, ntx, nty;
369 size_t strlength;
371 /* Only necessary when there will be no y-labels */
372 strlength = 0;
374 /* Draw the box */
375 ps_rgb(ps, BLACK);
376 ps_linewidth(ps, static_cast<int>(psr->boxlinewidth));
377 yy00 = y0;
378 for (i = 0; (i < nmat); i++)
380 dy = box_height(&(mat[i]), psr);
381 ps_box(ps, x0-1, yy00-1, x0+w+1, yy00+dy+1);
382 yy00 += dy+box_dh(psr)+box_dh_top(IS_ONCE, psr);
385 /* Draw the ticks on the axes */
386 ps_linewidth(ps, static_cast<int>(psr->ticklinewidth));
387 xx00 = x0-1;
388 yy00 = y0-1;
389 for (i = 0; (i < nmat); i++)
391 if (mat[i].flags & MAT_SPATIAL_X)
393 ntx = mat[i].nx + 1;
394 offset_x = 0.1;
396 else
398 ntx = mat[i].nx;
399 offset_x = 0.6;
401 if (mat[i].flags & MAT_SPATIAL_Y)
403 nty = mat[i].ny + 1;
404 offset_y = 0.1;
406 else
408 nty = mat[i].ny;
409 offset_y = 0.6;
411 snew(xtick, ntx);
412 for (j = 0; (j < ntx); j++)
414 sprintf(buf, "%g", mat[i].axis_x[j]);
415 xtick[j] = gmx_strdup(buf);
417 ps_strfont(ps, psr->X.tickfont, psr->X.tickfontsize);
418 for (x = 0; (x < ntx); x++)
420 xx = xx00 + (x + offset_x)*psr->xboxsize;
421 if ( ( bRmod(mat[i].axis_x[x], psr->X.offset, psr->X.major) ||
422 (psr->X.first && (x == 0))) &&
423 ( (i == 0) || box_do_all_x_maj_ticks(psr) ) )
425 /* Longer tick marks */
426 ps_line (ps, xx, yy00, xx, yy00-psr->X.majorticklen);
427 /* Plot label on lowest graph only */
428 if (i == 0)
430 ps_ctext(ps, xx,
431 yy00-DDD-psr->X.majorticklen-psr->X.tickfontsize*0.8,
432 xtick[x], eXCenter);
435 else if (bRmod(mat[i].axis_x[x], psr->X.offset, psr->X.minor) &&
436 ( (i == 0) || box_do_all_x_min_ticks(psr) ) )
438 /* Shorter tick marks */
439 ps_line(ps, xx, yy00, xx, yy00-psr->X.minorticklen);
441 else if (bRmod(mat[i].axis_x[x], psr->X.offset, psr->X.major) )
443 /* Even shorter marks, only each X.major */
444 ps_line(ps, xx, yy00, xx, yy00-(psr->boxspacing/2));
447 ps_strfont(ps, psr->Y.tickfont, psr->Y.tickfontsize);
448 snew(ytick, nty);
449 for (j = 0; (j < nty); j++)
451 sprintf(buf, "%g", mat[i].axis_y[j]);
452 ytick[j] = gmx_strdup(buf);
455 for (y = 0; (y < nty); y++)
457 yy = yy00 + (y + offset_y)*psr->yboxsize;
458 if (bRmod(mat[i].axis_y[y], psr->Y.offset, psr->Y.major) ||
459 (psr->Y.first && (y == 0)))
461 /* Major ticks */
462 strlength = std::max(strlength, std::strlen(ytick[y]));
463 ps_line (ps, xx00, yy, xx00-psr->Y.majorticklen, yy);
464 ps_ctext(ps, xx00-psr->Y.majorticklen-DDD,
465 yy-psr->Y.tickfontsize/3.0, ytick[y], eXRight);
467 else if (bRmod(mat[i].axis_y[y], psr->Y.offset, psr->Y.minor) )
469 /* Minor ticks */
470 ps_line(ps, xx00, yy, xx00-psr->Y.minorticklen, yy);
473 sfree(xtick);
474 sfree(ytick);
476 /* Label on Y-axis */
477 if (!psr->bYonce || i == nmat/2)
479 if (strlen(psr->Y.label) > 0)
481 mylab = psr->Y.label;
483 else
485 mylab = mat[i].label_y;
487 if (strlen(mylab) > 0)
489 ps_strfont(ps, psr->Y.font, psr->Y.fontsize);
490 ps_flip(ps, TRUE);
491 xxx = x0-psr->X.majorticklen-psr->X.tickfontsize*strlength-DDD;
492 ps_ctext(ps, yy00+box_height(&mat[i], psr)/2.0, 612.5-xxx,
493 mylab, eXCenter);
494 ps_flip(ps, FALSE);
498 yy00 += box_height(&(mat[i]), psr)+box_dh(psr)+box_dh_top(IS_ONCE, psr);
500 /* Label on X-axis */
501 if (strlen(psr->X.label) > 0)
503 mylab = psr->X.label;
505 else
507 mylab = mat[0].label_x;
509 if (strlen(mylab) > 0)
511 ps_strfont(ps, psr->X.font, psr->X.fontsize);
512 ps_ctext(ps, x0+w/2, y0-DDD-psr->X.majorticklen-psr->X.tickfontsize*FUDGE-
513 psr->X.fontsize, mylab, eXCenter);
517 static void draw_zerolines(t_psdata out, real x0, real y0, real w,
518 int nmat, t_matrix mat[], t_psrec *psr)
520 real xx, yy, dy, xx00, yy00;
521 int i, x, y;
523 xx00 = x0-1.5;
524 yy00 = y0-1.5;
525 ps_linewidth(out, static_cast<int>(psr->zerolinewidth));
526 for (i = 0; (i < nmat); i++)
528 dy = box_height(&(mat[i]), psr);
529 /* mat[i].axis_x and _y were already set by draw_boxes */
530 if (psr->X.lineatzero)
532 ps_rgb(out, linecolors[psr->X.lineatzero]);
533 for (x = 0; (x < mat[i].nx); x++)
535 xx = xx00+(x+0.7)*psr->xboxsize;
536 /* draw lines whenever tick label almost zero (e.g. next trajectory) */
537 if (x != 0 && x < mat[i].nx-1 &&
538 std::abs(mat[i].axis_x[x]) <
539 0.1*std::abs(mat[i].axis_x[x+1]-mat[i].axis_x[x]) )
541 ps_line (out, xx, yy00, xx, yy00+dy+2);
545 if (psr->Y.lineatzero)
547 ps_rgb(out, linecolors[psr->Y.lineatzero]);
548 for (y = 0; (y < mat[i].ny); y++)
550 yy = yy00+(y+0.7)*psr->yboxsize;
551 /* draw lines whenever tick label almost zero (e.g. next trajectory) */
552 if (y != 0 && y < mat[i].ny-1 &&
553 std::abs(mat[i].axis_y[y]) <
554 0.1*std::abs(mat[i].axis_y[y+1]-mat[i].axis_y[y]) )
556 ps_line (out, xx00, yy, xx00+w+2, yy);
560 yy00 += box_height(&(mat[i]), psr)+box_dh(psr)+box_dh_top(IS_ONCE, psr);
564 static void box_dim(int nmat, t_matrix mat[], t_matrix *mat2, t_psrec *psr,
565 int elegend, gmx_bool bFrame,
566 real *w, real *h, real *dw, real *dh)
568 int i, maxytick;
569 real ww, hh, dww, dhh;
571 hh = dww = dhh = 0;
572 maxytick = 0;
574 ww = 0;
575 for (i = 0; (i < nmat); i++)
577 ww = std::max(ww, mat[i].nx*psr->xboxsize);
578 hh += box_height(&(mat[i]), psr);
579 maxytick = std::max(maxytick, mat[i].nx);
581 if (bFrame)
583 if (mat[0].label_y[0])
585 dww += 2.0*(psr->Y.fontsize+DDD);
587 if (psr->Y.major > 0)
589 dww += psr->Y.majorticklen + DDD +
590 psr->Y.tickfontsize*(std::log(static_cast<real>(maxytick))/std::log(10.0));
592 else if (psr->Y.minor > 0)
594 dww += psr->Y.minorticklen;
597 if (mat[0].label_x[0])
599 dhh += psr->X.fontsize+2*DDD;
601 if ( /* fool emacs auto-indent */
602 (elegend == elBoth && (mat[0].legend[0] || (mat2 && mat2[0].legend[0]))) ||
603 (elegend == elFirst && mat[0].legend[0]) ||
604 (elegend == elSecond && (mat2 && mat2[0].legend[0])) )
606 dhh += 2*(psr->legfontsize*FUDGE+2*DDD);
608 else
610 dhh += psr->legfontsize*FUDGE+2*DDD;
612 if (psr->X.major > 0)
614 dhh += psr->X.tickfontsize*FUDGE+2*DDD+psr->X.majorticklen;
616 else if (psr->X.minor > 0)
618 dhh += psr->X.minorticklen;
621 hh += (nmat-1)*box_dh(psr);
622 hh += box_dh_top(TRUE, psr);
623 if (nmat > 1)
625 hh += (nmat-1)*box_dh_top(FALSE, psr);
628 *w = ww;
629 *h = hh;
630 *dw = dww;
631 *dh = dhh;
634 int add_maps(t_mapping **newmap,
635 int nmap1, t_mapping map1[], int nmap2, t_mapping map2[])
637 static char mapper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+{}|;:',<.>/?";
638 int nsymbols;
639 int nmap, j, k;
640 t_mapping *map;
642 nsymbols = std::strlen(mapper);
643 nmap = nmap1+nmap2;
644 if (nmap > nsymbols*nsymbols)
646 gmx_fatal(FARGS, "Not enough symbols to merge the two colormaps\n");
648 printf("Combining colormaps of %d and %d elements into one of %d elements\n",
649 nmap1, nmap2, nmap);
650 snew(map, nmap);
651 for (j = 0; j < nmap1; j++)
653 map[j].code.c1 = mapper[j % nsymbols];
654 if (nmap > nsymbols)
656 map[j].code.c2 = mapper[j/nsymbols];
658 map[j].rgb.r = map1[j].rgb.r;
659 map[j].rgb.g = map1[j].rgb.g;
660 map[j].rgb.b = map1[j].rgb.b;
661 map[j].desc = map1[j].desc;
663 for (j = 0; j < nmap2; j++)
665 k = j+nmap1;
666 map[k].code.c1 = mapper[k % nsymbols];
667 if (nmap > nsymbols)
669 map[k].code.c2 = mapper[k/nsymbols];
671 map[k].rgb.r = map2[j].rgb.r;
672 map[k].rgb.g = map2[j].rgb.g;
673 map[k].rgb.b = map2[j].rgb.b;
674 map[k].desc = map2[j].desc;
677 *newmap = map;
678 return nmap;
681 void xpm_mat(const char *outf, int nmat, t_matrix *mat, t_matrix *mat2,
682 gmx_bool bDiag, gmx_bool bFirstDiag)
684 FILE *out;
685 int i, x, y, col;
686 int nmap;
687 t_mapping *map = NULL;
689 out = gmx_ffopen(outf, "w");
691 for (i = 0; i < nmat; i++)
693 if (!mat2 || !diff_maps(mat[i].nmap, mat[i].map, mat2[i].nmap, mat2[i].map))
695 write_xpm_m(out, mat[0]);
697 else
699 nmap = add_maps(&map, mat[i].nmap, mat[i].map, mat2[i].nmap, mat2[i].map);
700 for (x = 0; (x < mat[i].nx); x++)
702 for (y = 0; (y < mat[i].nx); y++)
704 if ((x < y) || ((x == y) && bFirstDiag)) /* upper left -> map1 */
706 col = mat[i].matrix[x][y];
708 else /* lower right -> map2 */
710 col = mat[i].nmap+mat[i].matrix[x][y];
712 if ((bDiag) || (x != y))
714 mat[i].matrix[x][y] = col;
716 else
718 mat[i].matrix[x][y] = 0;
722 sfree(mat[i].map);
723 mat[i].nmap = nmap;
724 mat[i].map = map;
725 if (std::strcmp(mat[i].title, mat2[i].title) != 0)
727 sprintf(mat[i].title+strlen(mat[i].title), " / %s", mat2[i].title);
729 if (std::strcmp(mat[i].legend, mat2[i].legend) != 0)
731 sprintf(mat[i].legend+strlen(mat[i].legend), " / %s", mat2[i].legend);
733 write_xpm_m(out, mat[i]);
736 gmx_ffclose(out);
739 static void tick_spacing(int n, real axis[], real offset, char axisnm,
740 real *major, real *minor)
742 real space;
743 gmx_bool bTryAgain;
744 int i, j, t, f = 0, ten;
745 #define NFACT 4
746 real major_fact[NFACT] = {5, 4, 2, 1};
747 real minor_fact[NFACT] = {5, 4, 4, 5};
749 /* start with interval between 10 matrix points: */
750 space = std::max(10*axis[1]-axis[0], axis[std::min(10, n-1)]-axis[0]);
751 /* get power of 10 */
752 ten = static_cast<int>(std::ceil(std::log(space)/std::log(10.0))-1);
753 bTryAgain = TRUE;
754 for (t = ten+2; t > ten-3 && bTryAgain; t--)
756 for (f = 0; f < NFACT && bTryAgain; f++)
758 space = std::pow(static_cast<real>(10.0), static_cast<real>(t)) * major_fact[f];
759 /* count how many ticks we would get: */
760 i = 0;
761 for (j = 0; j < n; j++)
763 if (bRmod(axis[j], offset, space) )
765 i++;
768 /* do we have a reasonable number of ticks ? */
769 bTryAgain = (i > std::min(10, n-1)) || (i < 5);
772 if (bTryAgain)
774 space = std::max(10*axis[1]-axis[0], axis[std::min(10, n-1)]-axis[0]);
775 fprintf(stderr, "Auto tick spacing failed for %c-axis, guessing %g\n",
776 axisnm, space);
778 *major = space;
779 *minor = space / minor_fact[(f > 0) ? f-1 : 0];
780 fprintf(stderr, "Auto tick spacing for %c-axis: major %g, minor %g\n",
781 axisnm, *major, *minor);
784 void ps_mat(const char *outf, int nmat, t_matrix mat[], t_matrix mat2[],
785 gmx_bool bFrame, gmx_bool bDiag, gmx_bool bFirstDiag,
786 gmx_bool bTitle, gmx_bool bTitleOnce, gmx_bool bYonce, int elegend,
787 real size, real boxx, real boxy, const char *m2p, const char *m2pout,
788 int mapoffset)
790 const char *libm2p;
791 char *legend;
792 t_psdata out;
793 t_psrec psrec, *psr;
794 int W, H;
795 int i, x, y, col, leg = 0;
796 real x0, y0, xx;
797 real w, h, dw, dh;
798 int nmap1 = 0, nmap2 = 0, leg_nmap;
799 t_mapping *map1 = NULL, *map2 = NULL, *leg_map;
800 gmx_bool bMap1, bNextMap1, bDiscrete;
802 /* memory leak: */
803 libm2p = m2p ? gmxlibfn(m2p) : m2p;
804 get_params(libm2p, m2pout, &psrec);
806 psr = &psrec;
808 if (psr->X.major <= 0)
810 tick_spacing((mat[0].flags & MAT_SPATIAL_X) ? mat[0].nx + 1 : mat[0].nx,
811 mat[0].axis_x, psr->X.offset, 'X',
812 &(psr->X.major), &(psr->X.minor) );
814 if (psr->X.minor <= 0)
816 psr->X.minor = psr->X.major / 2;
818 if (psr->Y.major <= 0)
820 tick_spacing((mat[0].flags & MAT_SPATIAL_Y) ? mat[0].ny + 1 : mat[0].ny,
821 mat[0].axis_y, psr->Y.offset, 'Y',
822 &(psr->Y.major), &(psr->Y.minor) );
824 if (psr->Y.minor <= 0)
826 psr->Y.minor = psr->Y.major / 2;
829 if (boxx > 0)
831 psr->xboxsize = boxx;
832 psr->yboxsize = boxx;
834 if (boxy > 0)
836 psr->yboxsize = boxy;
839 if (psr->xboxsize == 0)
841 psr->xboxsize = size/mat[0].nx;
842 printf("Set the x-size of the box to %.3f\n", psr->xboxsize);
844 if (psr->yboxsize == 0)
846 psr->yboxsize = size/mat[0].nx;
847 printf("Set the y-size of the box to %.3f\n", psr->yboxsize);
850 nmap1 = 0;
851 for (i = 0; (i < nmat); i++)
853 if (mat[i].nmap > nmap1)
855 nmap1 = mat[i].nmap;
856 map1 = mat[i].map;
857 leg = i+1;
860 if (leg != 1)
862 printf("Selected legend of matrix # %d for display\n", leg);
864 if (mat2)
866 nmap2 = 0;
867 for (i = 0; (i < nmat); i++)
869 if (mat2[i].nmap > nmap2)
871 nmap2 = mat2[i].nmap;
872 map2 = mat2[i].map;
873 leg = i+1;
876 if (leg != 1)
878 printf("Selected legend of matrix # %d for second display\n", leg);
881 if ( (mat[0].legend[0] == 0) && psr->legend)
883 std::strcpy(mat[0].legend, psr->leglabel);
886 bTitle = bTitle && mat[nmat-1].title[0];
887 bTitleOnce = bTitleOnce && mat[nmat-1].title[0];
888 psr->bTitle = bTitle;
889 psr->bTitleOnce = bTitleOnce;
890 psr->bYonce = bYonce;
892 /* Set up size of box for nice colors */
893 box_dim(nmat, mat, mat2, psr, elegend, bFrame, &w, &h, &dw, &dh);
895 /* Set up bounding box */
896 W = static_cast<int>(w+dw);
897 H = static_cast<int>(h+dh);
899 /* Start box at */
900 x0 = dw;
901 y0 = dh;
902 x = static_cast<int>(W+psr->xoffs);
903 y = static_cast<int>(H+psr->yoffs);
904 if (bFrame)
906 x += 5*DDD;
907 y += 4*DDD;
909 out = ps_open(outf, 0, 0, x, y);
910 ps_linewidth(out, static_cast<int>(psr->linewidth));
911 ps_init_rgb_box(out, psr->xboxsize, psr->yboxsize);
912 ps_init_rgb_nbox(out, psr->xboxsize, psr->yboxsize);
913 ps_translate(out, psr->xoffs, psr->yoffs);
915 if (bFrame)
917 ps_comment(out, "Here starts the BOX drawing");
918 draw_boxes(out, x0, y0, w, nmat, mat, psr);
921 for (i = 0; (i < nmat); i++)
923 if (bTitle || (bTitleOnce && i == nmat-1) )
925 /* Print title, if any */
926 ps_rgb(out, BLACK);
927 ps_strfont(out, psr->titfont, psr->titfontsize);
928 std::string buf;
929 if (!mat2 || (std::strcmp(mat[i].title, mat2[i].title) == 0))
931 buf = mat[i].title;
933 else
935 buf = gmx::formatString("%s / %s", mat[i].title, mat2[i].title);
937 ps_ctext(out, x0+w/2, y0+box_height(&(mat[i]), psr)+psr->titfontsize,
938 buf.c_str(), eXCenter);
940 ps_comment(out, gmx::formatString("Here starts the filling of box #%d", i).c_str());
941 for (x = 0; (x < mat[i].nx); x++)
943 int nexty;
944 int nextcol;
946 xx = x0+x*psr->xboxsize;
947 ps_moveto(out, xx, y0);
948 y = 0;
949 bMap1 = (!mat2 || (x < y || (x == y && bFirstDiag)));
950 if ((bDiag) || (x != y))
952 col = mat[i].matrix[x][y];
954 else
956 col = -1;
958 for (nexty = 1; (nexty <= mat[i].ny); nexty++)
960 bNextMap1 = (!mat2 || (x < nexty || (x == nexty && bFirstDiag)));
961 /* TRUE: upper left -> map1 */
962 /* FALSE: lower right -> map2 */
963 if ((nexty == mat[i].ny) || (!bDiag && (x == nexty)))
965 nextcol = -1;
967 else
969 nextcol = mat[i].matrix[x][nexty];
971 if ( (nexty == mat[i].ny) || (col != nextcol) || (bMap1 != bNextMap1) )
973 if (col >= 0)
975 if (bMap1)
977 ps_rgb_nbox(out, &(mat[i].map[col].rgb), nexty-y);
979 else
981 assert(mat2);
982 ps_rgb_nbox(out, &(mat2[i].map[col].rgb), nexty-y);
985 else
987 ps_moverel(out, 0, psr->yboxsize);
989 y = nexty;
990 bMap1 = bNextMap1;
991 col = nextcol;
995 y0 += box_height(&(mat[i]), psr)+box_dh(psr)+box_dh_top(IS_ONCE, psr);
998 if (psr->X.lineatzero || psr->Y.lineatzero)
1000 /* reset y0 for first box */
1001 y0 = dh;
1002 ps_comment(out, "Here starts the zero lines drawing");
1003 draw_zerolines(out, x0, y0, w, nmat, mat, psr);
1006 if (elegend != elNone)
1008 ps_comment(out, "Now it's legend time!");
1009 ps_linewidth(out, static_cast<int>(psr->linewidth));
1010 if (mat2 == NULL || elegend != elSecond)
1012 bDiscrete = mat[0].bDiscrete;
1013 legend = mat[0].legend;
1014 leg_nmap = nmap1;
1015 leg_map = map1;
1017 else
1019 bDiscrete = mat2[0].bDiscrete;
1020 legend = mat2[0].legend;
1021 leg_nmap = nmap2;
1022 leg_map = map2;
1024 if (bDiscrete)
1026 leg_discrete(out, psr->legfontsize, DDD, legend,
1027 psr->legfontsize, psr->legfont, leg_nmap, leg_map);
1029 else
1031 if (elegend != elBoth)
1033 leg_continuous(out, x0+w/2, w/2, DDD, legend,
1034 psr->legfontsize, psr->legfont, leg_nmap, leg_map,
1035 mapoffset);
1037 else
1039 assert(mat2);
1040 leg_bicontinuous(out, x0+w/2, w, DDD, mat[0].legend, mat2[0].legend,
1041 psr->legfontsize, psr->legfont, nmap1, map1, nmap2, map2);
1044 ps_comment(out, "Were there, dude");
1047 ps_close(out);
1050 void make_axis_labels(int nmat, t_matrix *mat)
1052 int i, j;
1054 for (i = 0; (i < nmat); i++)
1056 /* Make labels for x axis */
1057 if (mat[i].axis_x == NULL)
1059 snew(mat[i].axis_x, mat[i].nx);
1060 for (j = 0; (j < mat[i].nx); j++)
1062 mat[i].axis_x[j] = j;
1065 /* Make labels for y axis */
1066 if (mat[i].axis_y == NULL)
1068 snew(mat[i].axis_y, mat[i].ny);
1069 for (j = 0; (j < mat[i].ny); j++)
1071 mat[i].axis_y[j] = j;
1077 void prune_mat(int nmat, t_matrix *mat, t_matrix *mat2, int skip)
1079 int i, x, y, xs, ys;
1081 for (i = 0; i < nmat; i++)
1083 fprintf(stderr, "converting %dx%d matrix to %dx%d\n",
1084 mat[i].nx, mat[i].ny,
1085 (mat[i].nx+skip-1)/skip, (mat[i].ny+skip-1)/skip);
1086 /* walk through matrix */
1087 xs = 0;
1088 for (x = 0; (x < mat[i].nx); x++)
1090 if (x % skip == 0)
1092 mat[i].axis_x[xs] = mat[i].axis_x[x];
1093 if (mat2)
1095 mat2[i].axis_x[xs] = mat2[i].axis_x[x];
1097 ys = 0;
1098 for (y = 0; (y < mat[i].ny); y++)
1100 if (x == 0)
1102 mat[i].axis_y[ys] = mat[i].axis_y[y];
1103 if (mat2)
1105 mat2[i].axis_y[ys] = mat2[i].axis_y[y];
1108 if (y % skip == 0)
1110 mat[i].matrix[xs][ys] = mat[i].matrix[x][y];
1111 if (mat2)
1113 mat2[i].matrix[xs][ys] = mat2[i].matrix[x][y];
1115 ys++;
1118 xs++;
1121 /* adjust parameters */
1122 mat[i].nx = (mat[i].nx+skip-1)/skip;
1123 mat[i].ny = (mat[i].ny+skip-1)/skip;
1124 if (mat2)
1126 mat2[i].nx = (mat2[i].nx+skip-1)/skip;
1127 mat2[i].ny = (mat2[i].ny+skip-1)/skip;
1132 void zero_lines(int nmat, t_matrix *mat, t_matrix *mat2)
1134 int i, x, y, m;
1135 t_matrix *mats;
1137 for (i = 0; i < nmat; i++)
1139 for (m = 0; m < (mat2 ? 2 : 1); m++)
1141 if (m == 0)
1143 mats = mat;
1145 else
1147 mats = mat2;
1149 for (x = 0; x < mats[i].nx-1; x++)
1151 if (std::abs(mats[i].axis_x[x+1]) < 1e-5)
1153 for (y = 0; y < mats[i].ny; y++)
1155 mats[i].matrix[x][y] = 0;
1159 for (y = 0; y < mats[i].ny-1; y++)
1161 if (std::abs(mats[i].axis_y[y+1]) < 1e-5)
1163 for (x = 0; x < mats[i].nx; x++)
1165 mats[i].matrix[x][y] = 0;
1173 void write_combined_matrix(int ecombine, const char *fn,
1174 int nmat, t_matrix *mat1, t_matrix *mat2,
1175 real *cmin, real *cmax)
1177 int i, j, k, nlevels;
1178 FILE *out;
1179 real **rmat1, **rmat2;
1180 real rhi, rlo;
1182 out = gmx_ffopen(fn, "w");
1183 for (k = 0; k < nmat; k++)
1185 if (mat2[k].nx != mat1[k].nx || mat2[k].ny != mat1[k].ny)
1187 gmx_fatal(FARGS, "Size of frame %d in 1st (%dx%d) and 2nd matrix (%dx%d) do"
1188 " not match.\n", k, mat1[k].nx, mat1[k].ny, mat2[k].nx, mat2[k].ny);
1190 printf("Combining two %dx%d matrices\n", mat1[k].nx, mat1[k].ny);
1191 rmat1 = matrix2real(&mat1[k], NULL);
1192 rmat2 = matrix2real(&mat2[k], NULL);
1193 if (NULL == rmat1 || NULL == rmat2)
1195 gmx_fatal(FARGS, "Could not extract real data from %s xpm matrices. Note that, e.g.,\n"
1196 "g_rms and g_mdmat provide such data, but not do_dssp.\n",
1197 (NULL == rmat1 && NULL == rmat2) ? "both" : "one of the" );
1199 rlo = 1e38;
1200 rhi = -1e38;
1201 for (j = 0; j < mat1[k].ny; j++)
1203 for (i = 0; i < mat1[k].nx; i++)
1205 switch (ecombine)
1207 case ecAdd: rmat1[i][j] += rmat2[i][j]; break;
1208 case ecSub: rmat1[i][j] -= rmat2[i][j]; break;
1209 case ecMult: rmat1[i][j] *= rmat2[i][j]; break;
1210 case ecDiv: rmat1[i][j] /= rmat2[i][j]; break;
1211 default:
1212 gmx_fatal(FARGS, "No such combination rule %d for matrices", ecombine);
1214 rlo = std::min(rlo, rmat1[i][j]);
1215 rhi = std::max(rhi, rmat1[i][j]);
1218 if (cmin)
1220 rlo = *cmin;
1222 if (cmax)
1224 rhi = *cmax;
1226 nlevels = std::max(mat1[k].nmap, mat2[k].nmap);
1227 if (rhi == rlo)
1229 fprintf(stderr,
1230 "combination results in uniform matrix (%g), no output\n", rhi);
1233 else if (rlo>=0 || rhi<=0)
1234 write_xpm(out, mat1[k].flags, mat1[k].title, mat1[k].legend,
1235 mat1[k].label_x, mat1[k].label_y,
1236 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
1237 rmat1, rlo, rhi, rhi<=0?red:white, rhi<=0?white:blue,
1238 &nlevels);
1239 else
1240 write_xpm3(out, mat2[k].flags, mat1[k].title, mat1[k].legend,
1241 mat1[k].label_x, mat1[k].label_y,
1242 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
1243 rmat1, rlo, 0, rhi, red, white, blue, &nlevels);
1245 else
1247 write_xpm(out, mat1[k].flags, mat1[k].title, mat1[k].legend,
1248 mat1[k].label_x, mat1[k].label_y,
1249 mat1[k].nx, mat1[k].ny, mat1[k].axis_x, mat1[k].axis_y,
1250 rmat1, rlo, rhi, white, black, &nlevels);
1253 gmx_ffclose(out);
1256 void do_mat(int nmat, t_matrix *mat, t_matrix *mat2,
1257 gmx_bool bFrame, gmx_bool bZeroLine, gmx_bool bDiag, gmx_bool bFirstDiag, gmx_bool bTitle,
1258 gmx_bool bTitleOnce, gmx_bool bYonce, int elegend,
1259 real size, real boxx, real boxy,
1260 const char *epsfile, const char *xpmfile, const char *m2p,
1261 const char *m2pout, int skip, int mapoffset)
1263 int i, j, k;
1265 if (mat2)
1267 for (k = 0; (k < nmat); k++)
1269 if ((mat2[k].nx != mat[k].nx) || (mat2[k].ny != mat[k].ny))
1271 gmx_fatal(FARGS, "WAKE UP!! Size of frame %d in 2nd matrix file (%dx%d) does not match size of 1st matrix (%dx%d) or the other way around.\n",
1272 k, mat2[k].nx, mat2[k].ny, mat[k].nx, mat[k].ny);
1274 for (j = 0; (j < mat[k].ny); j++)
1276 for (i = bFirstDiag ? j+1 : j; (i < mat[k].nx); i++)
1278 mat[k].matrix[i][j] = mat2[k].matrix[i][j];
1283 for (i = 0; (i < nmat); i++)
1285 fprintf(stderr, "Matrix %d is %d x %d\n", i, mat[i].nx, mat[i].ny);
1288 make_axis_labels(nmat, mat);
1290 if (skip > 1)
1292 prune_mat(nmat, mat, mat2, skip);
1295 if (bZeroLine)
1297 zero_lines(nmat, mat, mat);
1300 if (epsfile != NULL)
1302 ps_mat(epsfile, nmat, mat, mat2, bFrame, bDiag, bFirstDiag,
1303 bTitle, bTitleOnce, bYonce, elegend,
1304 size, boxx, boxy, m2p, m2pout, mapoffset);
1306 if (xpmfile != NULL)
1308 xpm_mat(xpmfile, nmat, mat, mat2, bDiag, bFirstDiag);
1312 void gradient_map(rvec grad, int nmap, t_mapping map[])
1314 int i;
1315 real c;
1317 for (i = 0; i < nmap; i++)
1319 c = i/(nmap-1.0);
1320 map[i].rgb.r = 1-c*(1-grad[XX]);
1321 map[i].rgb.g = 1-c*(1-grad[YY]);
1322 map[i].rgb.b = 1-c*(1-grad[ZZ]);
1326 void gradient_mat(rvec grad, int nmat, t_matrix mat[])
1328 int m;
1330 for (m = 0; m < nmat; m++)
1332 gradient_map(grad, mat[m].nmap, mat[m].map);
1336 void rainbow_map(gmx_bool bBlue, int nmap, t_mapping map[])
1338 int i;
1339 real c, r, g, b;
1341 for (i = 0; i < nmap; i++)
1343 c = (map[i].rgb.r + map[i].rgb.g + map[i].rgb.b)/3;
1344 if (c > 1)
1346 c = 1;
1348 if (bBlue)
1350 c = 1 - c;
1352 if (c <= 0.25) /* 0-0.25 */
1354 r = 0;
1355 g = std::pow(4.0*c, 2.0/3.0);
1356 b = 1;
1358 else if (c <= 0.5) /* 0.25-0.5 */
1360 r = 0;
1361 g = 1;
1362 b = std::pow(2.0-4.0*c, 2.0/3.0);
1364 else if (c <= 0.75) /* 0.5-0.75 */
1366 r = std::pow(4.0*c-2.0, 2.0/3.0);
1367 g = 1;
1368 b = 0;
1370 else /* 0.75-1 */
1372 r = 1;
1373 g = std::pow(4.0-4.0*c, 2.0/3.0);
1374 b = 0;
1376 map[i].rgb.r = r;
1377 map[i].rgb.g = g;
1378 map[i].rgb.b = b;
1382 void rainbow_mat(gmx_bool bBlue, int nmat, t_matrix mat[])
1384 int m;
1386 for (m = 0; m < nmat; m++)
1388 rainbow_map(bBlue, mat[m].nmap, mat[m].map);
1392 int gmx_xpm2ps(int argc, char *argv[])
1394 const char *desc[] = {
1395 "[THISMODULE] makes a beautiful color plot of an XPixelMap file.",
1396 "Labels and axis can be displayed, when they are supplied",
1397 "in the correct matrix format.",
1398 "Matrix data may be generated by programs such as [gmx-do_dssp], [gmx-rms] or",
1399 "[gmx-mdmat].[PAR]",
1400 "Parameters are set in the [TT].m2p[tt] file optionally supplied with",
1401 "[TT]-di[tt]. Reasonable defaults are provided. Settings for the [IT]y[it]-axis",
1402 "default to those for the [IT]x[it]-axis. Font names have a defaulting hierarchy:",
1403 "titlefont -> legendfont; titlefont -> (xfont -> yfont -> ytickfont)",
1404 "-> xtickfont, e.g. setting titlefont sets all fonts, setting xfont",
1405 "sets yfont, ytickfont and xtickfont.[PAR]",
1406 "When no [TT].m2p[tt] file is supplied, many settings are taken from",
1407 "command line options. The most important option is [TT]-size[tt],",
1408 "which sets the size of the whole matrix in postscript units.",
1409 "This option can be overridden with the [TT]-bx[tt] and [TT]-by[tt]",
1410 "options (and the corresponding parameters in the [TT].m2p[tt] file),",
1411 "which set the size of a single matrix element.[PAR]",
1412 "With [TT]-f2[tt] a second matrix file can be supplied. Both matrix",
1413 "files will be read simultaneously and the upper left half of the",
1414 "first one ([TT]-f[tt]) is plotted together with the lower right",
1415 "half of the second one ([TT]-f2[tt]). The diagonal will contain",
1416 "values from the matrix file selected with [TT]-diag[tt].",
1417 "Plotting of the diagonal values can be suppressed altogether by",
1418 "setting [TT]-diag[tt] to [TT]none[tt].",
1419 "In this case, a new color map will be generated with",
1420 "a red gradient for negative numbers and a blue for positive.",
1421 "If the color coding and legend labels of both matrices are identical,",
1422 "only one legend will be displayed, else two separate legends are",
1423 "displayed.",
1424 "With [TT]-combine[tt], an alternative operation can be selected",
1425 "to combine the matrices. The output range is automatically set",
1426 "to the actual range of the combined matrix. This can be overridden",
1427 "with [TT]-cmin[tt] and [TT]-cmax[tt].[PAR]",
1428 "[TT]-title[tt] can be set to [TT]none[tt] to suppress the title, or to",
1429 "[TT]ylabel[tt] to show the title in the Y-label position (alongside",
1430 "the [IT]y[it]-axis).[PAR]",
1431 "With the [TT]-rainbow[tt] option, dull grayscale matrices can be turned",
1432 "into attractive color pictures.[PAR]",
1433 "Merged or rainbowed matrices can be written to an XPixelMap file with",
1434 "the [TT]-xpm[tt] option."
1437 gmx_output_env_t *oenv;
1438 const char *fn, *epsfile = NULL, *xpmfile = NULL;
1439 int i, nmat, nmat2, etitle, elegend, ediag, erainbow, ecombine;
1440 t_matrix *mat = NULL, *mat2 = NULL;
1441 gmx_bool bTitle, bTitleOnce, bDiag, bFirstDiag, bGrad;
1442 static gmx_bool bFrame = TRUE, bZeroLine = FALSE, bYonce = FALSE;
1443 static real size = 400, boxx = 0, boxy = 0, cmin = 0, cmax = 0;
1444 static rvec grad = {0, 0, 0};
1445 enum {
1446 etSel, etTop, etOnce, etYlabel, etNone, etNR
1448 const char *title[] = { NULL, "top", "once", "ylabel", "none", NULL };
1449 /* MUST correspond to enum elXxx as defined at top of file */
1450 const char *legend[] = { NULL, "both", "first", "second", "none", NULL };
1451 enum {
1452 edSel, edFirst, edSecond, edNone, edNR
1454 const char *diag[] = { NULL, "first", "second", "none", NULL };
1455 enum {
1456 erSel, erNo, erBlue, erRed, erNR
1458 const char *rainbow[] = { NULL, "no", "blue", "red", NULL };
1459 /* MUST correspond to enum ecXxx as defined at top of file */
1460 const char *combine[] = {
1461 NULL, "halves", "add", "sub", "mult", "div", NULL
1463 static int skip = 1, mapoffset = 0;
1464 t_pargs pa[] = {
1465 { "-frame", FALSE, etBOOL, {&bFrame},
1466 "Display frame, ticks, labels, title and legend" },
1467 { "-title", FALSE, etENUM, {title}, "Show title at" },
1468 { "-yonce", FALSE, etBOOL, {&bYonce}, "Show y-label only once" },
1469 { "-legend", FALSE, etENUM, {legend}, "Show legend" },
1470 { "-diag", FALSE, etENUM, {diag}, "Diagonal" },
1471 { "-size", FALSE, etREAL, {&size},
1472 "Horizontal size of the matrix in ps units" },
1473 { "-bx", FALSE, etREAL, {&boxx},
1474 "Element x-size, overrides [TT]-size[tt] (also y-size when [TT]-by[tt] is not set)" },
1475 { "-by", FALSE, etREAL, {&boxy}, "Element y-size" },
1476 { "-rainbow", FALSE, etENUM, {rainbow},
1477 "Rainbow colors, convert white to" },
1478 { "-gradient", FALSE, etRVEC, {grad},
1479 "Re-scale colormap to a smooth gradient from white {1,1,1} to {r,g,b}" },
1480 { "-skip", FALSE, etINT, {&skip},
1481 "only write out every nr-th row and column" },
1482 { "-zeroline", FALSE, etBOOL, {&bZeroLine},
1483 "insert line in [REF].xpm[ref] matrix where axis label is zero"},
1484 { "-legoffset", FALSE, etINT, {&mapoffset},
1485 "Skip first N colors from [REF].xpm[ref] file for the legend" },
1486 { "-combine", FALSE, etENUM, {combine}, "Combine two matrices" },
1487 { "-cmin", FALSE, etREAL, {&cmin}, "Minimum for combination output" },
1488 { "-cmax", FALSE, etREAL, {&cmax}, "Maximum for combination output" }
1490 #define NPA asize(pa)
1491 t_filenm fnm[] = {
1492 { efXPM, "-f", NULL, ffREAD },
1493 { efXPM, "-f2", "root2", ffOPTRD },
1494 { efM2P, "-di", NULL, ffLIBOPTRD },
1495 { efM2P, "-do", "out", ffOPTWR },
1496 { efEPS, "-o", NULL, ffOPTWR },
1497 { efXPM, "-xpm", NULL, ffOPTWR }
1499 #define NFILE asize(fnm)
1501 if (!parse_common_args(&argc, argv, PCA_CAN_VIEW,
1502 NFILE, fnm, NPA, pa,
1503 asize(desc), desc, 0, NULL, &oenv))
1505 return 0;
1508 etitle = nenum(title);
1509 elegend = nenum(legend);
1510 ediag = nenum(diag);
1511 erainbow = nenum(rainbow);
1512 ecombine = nenum(combine);
1513 bGrad = opt2parg_bSet("-gradient", NPA, pa);
1514 for (i = 0; i < DIM; i++)
1516 if (grad[i] < 0 || grad[i] > 1)
1518 gmx_fatal(FARGS, "RGB value %g out of range (0.0-1.0)", grad[i]);
1521 if (!bFrame)
1523 etitle = etNone;
1524 elegend = elNone;
1527 epsfile = ftp2fn_null(efEPS, NFILE, fnm);
1528 xpmfile = opt2fn_null("-xpm", NFILE, fnm);
1529 if (epsfile == NULL && xpmfile == NULL)
1531 if (ecombine != ecHalves)
1533 xpmfile = opt2fn("-xpm", NFILE, fnm);
1535 else
1537 epsfile = ftp2fn(efEPS, NFILE, fnm);
1540 if (ecombine != ecHalves && epsfile)
1542 fprintf(stderr,
1543 "WARNING: can only write result of arithmetic combination "
1544 "of two matrices to .xpm file\n"
1545 " file %s will not be written\n", epsfile);
1546 epsfile = NULL;
1549 bDiag = ediag != edNone;
1550 bFirstDiag = ediag != edSecond;
1552 fn = opt2fn("-f", NFILE, fnm);
1553 nmat = read_xpm_matrix(fn, &mat);
1554 fprintf(stderr, "There %s %d matri%s in %s\n", (nmat > 1) ? "are" : "is", nmat, (nmat > 1) ? "ces" : "x", fn);
1555 fn = opt2fn_null("-f2", NFILE, fnm);
1556 if (fn)
1558 nmat2 = read_xpm_matrix(fn, &mat2);
1559 fprintf(stderr, "There %s %d matri%s in %s\n", (nmat2 > 1) ? "are" : "is", nmat2, (nmat2 > 1) ? "ces" : "x", fn);
1560 if (nmat != nmat2)
1562 fprintf(stderr, "Different number of matrices, using the smallest number.\n");
1563 nmat = nmat2 = std::min(nmat, nmat2);
1566 else
1568 if (ecombine != ecHalves)
1570 fprintf(stderr,
1571 "WARNING: arithmetic matrix combination selected (-combine), "
1572 "but no second matrix (-f2) supplied\n"
1573 " no matrix combination will be performed\n");
1575 ecombine = 0;
1576 nmat2 = 0;
1578 bTitle = etitle == etTop;
1579 bTitleOnce = etitle == etOnce;
1580 if (etitle == etYlabel)
1582 for (i = 0; (i < nmat); i++)
1584 std::strcpy(mat[i].label_y, mat[i].title);
1585 if (mat2)
1587 std::strcpy(mat2[i].label_y, mat2[i].title);
1591 if (bGrad)
1593 gradient_mat(grad, nmat, mat);
1594 if (mat2)
1596 gradient_mat(grad, nmat2, mat2);
1599 if (erainbow != erNo)
1601 rainbow_mat(erainbow == erBlue, nmat, mat);
1602 if (mat2)
1604 rainbow_mat(erainbow == erBlue, nmat2, mat2);
1608 if ((mat2 == NULL) && (elegend != elNone))
1610 elegend = elFirst;
1613 if (ecombine && ecombine != ecHalves)
1615 write_combined_matrix(ecombine, xpmfile, nmat, mat, mat2,
1616 opt2parg_bSet("-cmin", NPA, pa) ? &cmin : NULL,
1617 opt2parg_bSet("-cmax", NPA, pa) ? &cmax : NULL);
1619 else
1621 do_mat(nmat, mat, mat2, bFrame, bZeroLine, bDiag, bFirstDiag,
1622 bTitle, bTitleOnce, bYonce,
1623 elegend, size, boxx, boxy, epsfile, xpmfile,
1624 opt2fn_null("-di", NFILE, fnm), opt2fn_null("-do", NFILE, fnm), skip,
1625 mapoffset);
1628 view_all(oenv, NFILE, fnm);
1630 return 0;