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,2017,2018 by the GROMACS development team.
7 * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
52 #include "gromacs/fileio/gmxfio.h"
53 #include "gromacs/math/functions.h"
54 #include "gromacs/math/utilities.h"
55 #include "gromacs/utility/binaryinformation.h"
56 #include "gromacs/utility/cstringutil.h"
57 #include "gromacs/utility/exceptions.h"
58 #include "gromacs/utility/fatalerror.h"
59 #include "gromacs/utility/futil.h"
60 #include "gromacs/utility/programcontext.h"
61 #include "gromacs/utility/smalloc.h"
65 static const char mapper[] =
66 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+{}|;:',<.>/"
68 #define NMAP static_cast<long int>(sizeof(mapper) / sizeof(mapper[0]))
70 #define MAX_XPM_LINELENGTH 4096
72 real** mk_matrix(int nx, int ny, gmx_bool b1D)
83 for (i = 0; (i < nx); i++)
87 m[i] = &(m[0][i * ny]);
98 void done_matrix(int nx, real*** m)
102 for (i = 0; (i < nx); i++)
110 static bool operator==(t_xpmelmt e1, t_xpmelmt e2)
112 return (e1.c1 == e2.c1) && (e1.c2 == e2.c2);
115 //! Return the index of the first element that matches \c c, or -1 if not found.
116 t_matelmt searchcmap(ArrayRef<const t_mapping> map, t_xpmelmt c)
118 auto findIt = std::find_if(map.begin(), map.end(), [&c](const auto& m) { return (m.code == c); });
119 return (findIt == map.end()) ? -1 : (findIt - map.begin());
122 //! Read the mapping table from in, return number of entries
123 static std::vector<t_mapping> getcmap(FILE* in, const char* fn)
127 char code[STRLEN], desc[STRLEN];
129 std::vector<t_mapping> m;
131 if (fgets2(line, STRLEN - 1, in) == nullptr)
134 "Not enough lines in colormap file %s"
135 "(just wanted to read number of entries)",
138 sscanf(line, "%d", &n);
140 for (i = 0; (i < n); i++)
142 if (fgets2(line, STRLEN - 1, in) == nullptr)
145 "Not enough lines in colormap file %s"
146 "(should be %d, found only %d)",
151 sscanf(line, "%s%s%lf%lf%lf", code, desc, &r, &g, &b);
152 m[i].code.c1 = code[0];
154 m[i].desc = gmx_strdup(desc);
163 std::vector<t_mapping> readcmap(const char* fn)
165 FilePtr in = openLibraryFile(fn);
166 return getcmap(in.get(), fn);
169 void printcmap(FILE* out, int n, t_mapping map[])
173 fprintf(out, "%d\n", n);
174 for (i = 0; (i < n); i++)
177 "%c%c %20s %10g %10g %10g\n",
178 map[i].code.c1 ? map[i].code.c1 : ' ',
179 map[i].code.c2 ? map[i].code.c2 : ' ',
187 void writecmap(const char* fn, int n, t_mapping map[])
191 out = gmx_fio_fopen(fn, "w");
192 printcmap(out, n, map);
196 static char* fgetline(char** line, int llmax, int* llalloc, FILE* in)
200 if (llmax > *llalloc)
202 srenew(*line, llmax + 1);
205 fg = fgets(*line, llmax, in);
211 static void skipstr(char* line)
217 while ((line[c] != ' ') && (line[c] != '\0'))
222 while (line[c] != '\0')
224 line[c - i] = line[c];
230 static char* line2string(char** line)
234 if (*line != nullptr)
236 while (((*line)[0] != '\"') && ((*line)[0] != '\0'))
241 if ((*line)[0] != '\"')
248 while (((*line)[i] != '\"') && ((*line)[i] != '\0'))
253 if ((*line)[i] != '\"')
266 //! If a label named \c label is found in \c line, return it. Otherwise return empty string.
267 static std::optional<std::string> findLabelInLine(const std::string& line, const std::string& label)
269 std::regex re(".*\\s" + label + ":[\\s]*\"(.*)\"");
271 if (std::regex_search(line, match, re) && match.size() > 1)
273 return std::make_optional<std::string>(match.str(1));
278 //! Read and return a matrix from \c in
279 static t_matrix read_xpm_entry(FILE* in)
281 char * line_buf = nullptr, *line = nullptr, *str;
282 std::optional<std::string> title, legend, xLabel, yLabel, matrixType;
283 int i, m, col_len, nch = 0, llmax;
285 unsigned int r, g, b;
287 gmx_bool bGetOnWithIt, bSetLine;
292 while ((nullptr != fgetline(&line_buf, llmax, &llalloc, in))
293 && (std::strncmp(line_buf, "static", 6) != 0))
295 std::string lineString = line_buf;
296 if (!title.has_value())
298 title = findLabelInLine(lineString, "title");
300 if (!legend.has_value())
302 legend = findLabelInLine(lineString, "legend");
304 if (!xLabel.has_value())
306 xLabel = findLabelInLine(lineString, "x-label");
308 if (!yLabel.has_value())
310 yLabel = findLabelInLine(lineString, "y-label");
312 if (!matrixType.has_value())
314 matrixType = findLabelInLine(lineString, "type");
318 if (!line_buf || strncmp(line_buf, "static", 6) != 0)
320 gmx_input("Invalid XPixMap");
325 mm.title = title.value_or("");
326 mm.legend = legend.value_or("");
327 mm.label_x = xLabel.value_or("");
328 mm.label_y = yLabel.value_or("");
330 if (matrixType.has_value() && (gmx_strcasecmp(matrixType->c_str(), "Discrete") == 0))
347 bGetOnWithIt = FALSE;
348 while (!bGetOnWithIt && (nullptr != fgetline(&line_buf, llmax, &llalloc, in)))
351 while ((line[0] != '\"') && (line[0] != '\0'))
359 sscanf(line, "%d %d %d %d", &(mm.nx), &(mm.ny), &nmap, &nch);
362 gmx_fatal(FARGS, "Sorry can only read xpm's with at most 2 characters per pixel\n");
364 if (mm.nx <= 0 || mm.ny <= 0)
366 gmx_fatal(FARGS, "Dimensions of xpm-file have to be larger than 0\n");
368 llmax = std::max(STRLEN, mm.nx + 10);
374 fprintf(debug, "mm.nx %d mm.ny %d nmap %d nch %d\n", mm.nx, mm.ny, nmap, nch);
378 gmx_fatal(FARGS, "Number of characters per pixel not found in xpm\n");
384 while ((m < nmap) && (nullptr != fgetline(&line_buf, llmax, &llalloc, in)))
386 line = std::strchr(line_buf, '\"');
390 /* Read xpm color map entry */
391 mm.map[m].code.c1 = line[0];
394 mm.map[m].code.c2 = 0;
398 mm.map[m].code.c2 = line[1];
401 str = std::strchr(line, '#');
406 while (std::isxdigit(str[col_len]))
412 sscanf(line, "%*s #%2x%2x%2x", &r, &g, &b);
413 mm.map[m].rgb.r = r / 255.0;
414 mm.map[m].rgb.g = g / 255.0;
415 mm.map[m].rgb.b = b / 255.0;
417 else if (col_len == 12)
419 sscanf(line, "%*s #%4x%4x%4x", &r, &g, &b);
420 mm.map[m].rgb.r = r / 65535.0;
421 mm.map[m].rgb.g = g / 65535.0;
422 mm.map[m].rgb.b = b / 65535.0;
426 gmx_file("Unsupported or invalid colormap in X PixMap");
431 str = std::strchr(line, 'c');
438 gmx_file("Unsupported or invalid colormap in X PixMap");
440 fprintf(stderr, "Using white for color \"%s", str);
445 line = std::strchr(line, '\"');
448 mm.map[m].desc = gmx_strdup(line);
455 "Number of read colors map entries (%d) does not match the number in the header "
461 /* Read axes, if there are any */
470 GMX_RELEASE_ASSERT(line, "Need to have valid line to parse");
471 if (strstr(line, "x-axis"))
473 line = std::strstr(line, "x-axis");
475 mm.axis_x.reserve(mm.nx + 1);
476 while (sscanf(line, "%lf", &u) == 1)
478 if (ssize(mm.axis_x) > mm.nx)
480 gmx_fatal(FARGS, "Too many x-axis labels in xpm (max %d)", mm.nx);
482 else if (ssize(mm.axis_x) == mm.nx)
484 mm.flags |= MAT_SPATIAL_X;
486 mm.axis_x.push_back(u);
490 else if (std::strstr(line, "y-axis"))
492 line = std::strstr(line, "y-axis");
494 mm.axis_y.reserve(mm.ny + 1);
495 while (sscanf(line, "%lf", &u) == 1)
497 if (ssize(mm.axis_y) > mm.ny)
499 gmx_fatal(FARGS, "Too many y-axis labels in xpm (max %d)", mm.ny);
501 else if (ssize(mm.axis_y) == mm.ny)
503 mm.flags |= MAT_SPATIAL_Y;
505 mm.axis_y.push_back(u);
509 } while ((line[0] != '\"') && (nullptr != fgetline(&line_buf, llmax, &llalloc, in)));
512 mm.matrix.resize(mm.nx, mm.ny);
513 int rowIndex = mm.ny - 1;
522 if (rowIndex % (1 + mm.ny / 100) == 0)
524 fprintf(stderr, "%3d%%\b\b\b\b", (100 * (mm.ny - rowIndex)) / mm.ny);
526 while ((line[0] != '\"') && (line[0] != '\0'))
532 gmx_fatal(FARGS, "Not enough characters in row %d of the matrix\n", rowIndex + 1);
537 for (i = 0; i < mm.nx; i++)
539 c.c1 = line[nch * i];
546 c.c2 = line[nch * i + 1];
548 mm.matrix(i, rowIndex) = searchcmap(mm.map, c);
552 } while ((rowIndex >= 0) && (nullptr != fgetline(&line_buf, llmax, &llalloc, in)));
555 gmx_incons("Not enough rows in the matrix");
562 std::vector<t_matrix> read_xpm_matrix(const char* fnm)
565 char* line = nullptr;
568 in = gmx_fio_fopen(fnm, "r");
570 std::vector<t_matrix> mat;
571 while (nullptr != fgetline(&line, STRLEN, &llalloc, in))
573 if (std::strstr(line, "/* XPM */"))
575 mat.emplace_back(read_xpm_entry(in));
582 gmx_file("Invalid XPixMap");
590 real** matrix2real(t_matrix* in, real** out)
594 std::vector<real> rmap(in->map.size());
596 for (gmx::index i = 0; i != ssize(in->map); ++i)
598 if ((in->map[i].desc == nullptr) || (sscanf(in->map[i].desc, "%lf", &tmp) != 1))
601 "Could not convert matrix to reals,\n"
602 "color map entry %zd has a non-real description: \"%s\"\n",
613 for (int i = 0; i < in->nx; i++)
615 snew(out[i], in->ny);
618 for (int i = 0; i < in->nx; i++)
620 for (int j = 0; j < in->ny; j++)
622 out[i][j] = rmap[in->matrix(i, j)];
626 fprintf(stderr, "Converted a %dx%d matrix with %zu levels to reals\n", in->nx, in->ny, in->map.size());
631 static void write_xpm_header(FILE* out,
632 const std::string& title,
633 const std::string& legend,
634 const std::string& label_x,
635 const std::string& label_y,
638 fprintf(out, "/* XPM */\n");
639 fprintf(out, "/* This file can be converted to EPS by the GROMACS program xpm2ps */\n");
640 fprintf(out, "/* title: \"%s\" */\n", title.c_str());
641 fprintf(out, "/* legend: \"%s\" */\n", legend.c_str());
642 fprintf(out, "/* x-label: \"%s\" */\n", label_x.c_str());
643 fprintf(out, "/* y-label: \"%s\" */\n", label_y.c_str());
646 fprintf(out, "/* type: \"Discrete\" */\n");
650 fprintf(out, "/* type: \"Continuous\" */\n");
654 static int calc_nmid(int nlevels, real lo, real mid, real hi)
656 /* Take care that we have at least 1 entry in the mid to hi range
658 return std::min(std::max(0, static_cast<int>(((mid - lo) / (hi - lo)) * (nlevels - 1))), nlevels - 1);
662 write_xpm_map3(FILE* out, int n_x, int n_y, int* nlevels, real lo, real mid, real hi, t_rgb rlo, t_rgb rmid, t_rgb rhi)
665 double r, g, b, clev_lo, clev_hi;
667 if (*nlevels > NMAP * NMAP)
670 "Warning, too many levels (%d) in matrix, using %d only\n",
672 static_cast<int>(NMAP * NMAP));
673 *nlevels = NMAP * NMAP;
675 else if (*nlevels < 2)
677 fprintf(stderr, "Warning, too few levels (%d) in matrix, using 2 instead\n", *nlevels);
680 if (!((mid >= lo) && (mid < hi)))
682 gmx_fatal(FARGS, "Lo: %f, Mid: %f, Hi: %f\n", lo, mid, hi);
685 fprintf(out, "static char *gromacs_xpm[] = {\n");
686 fprintf(out, "\"%d %d %d %d\",\n", n_x, n_y, *nlevels, (*nlevels <= NMAP) ? 1 : 2);
688 nmid = calc_nmid(*nlevels, lo, mid, hi);
690 clev_hi = (*nlevels - 1 - nmid);
691 for (i = 0; (i < nmid); i++)
693 r = rlo.r + (i * (rmid.r - rlo.r) / clev_lo);
694 g = rlo.g + (i * (rmid.g - rlo.g) / clev_lo);
695 b = rlo.b + (i * (rmid.b - rlo.b) / clev_lo);
697 "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n",
699 (*nlevels <= NMAP) ? ' ' : mapper[i / NMAP],
700 static_cast<unsigned int>(std::round(255 * r)),
701 static_cast<unsigned int>(std::round(255 * g)),
702 static_cast<unsigned int>(std::round(255 * b)),
703 ((nmid - i) * lo + i * mid) / clev_lo);
705 for (i = 0; (i < (*nlevels - nmid)); i++)
707 r = rmid.r + (i * (rhi.r - rmid.r) / clev_hi);
708 g = rmid.g + (i * (rhi.g - rmid.g) / clev_hi);
709 b = rmid.b + (i * (rhi.b - rmid.b) / clev_hi);
711 "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n",
712 mapper[(i + nmid) % NMAP],
713 (*nlevels <= NMAP) ? ' ' : mapper[(i + nmid) / NMAP],
714 static_cast<unsigned int>(std::round(255 * r)),
715 static_cast<unsigned int>(std::round(255 * g)),
716 static_cast<unsigned int>(std::round(255 * b)),
717 ((*nlevels - 1 - nmid - i) * mid + i * hi) / clev_hi);
721 static void pr_simple_cmap(FILE* out, real lo, real hi, int nlevel, t_rgb rlo, t_rgb rhi, int i0)
726 for (i = 0; (i < nlevel); i++)
728 fac = (i + 1.0) / (nlevel);
729 r = rlo.r + fac * (rhi.r - rlo.r);
730 g = rlo.g + fac * (rhi.g - rlo.g);
731 b = rlo.b + fac * (rhi.b - rlo.b);
733 "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n",
734 mapper[(i + i0) % NMAP],
735 (nlevel <= NMAP) ? ' ' : mapper[(i + i0) / NMAP],
736 static_cast<unsigned int>(std::round(255 * r)),
737 static_cast<unsigned int>(std::round(255 * g)),
738 static_cast<unsigned int>(std::round(255 * b)),
739 lo + fac * (hi - lo));
743 static void pr_discrete_cmap(FILE* out, int* nlevel, int i0)
746 { 1.0, 1.0, 1.0 }, /* white */
747 { 1.0, 0.0, 0.0 }, /* red */
748 { 1.0, 1.0, 0.0 }, /* yellow */
749 { 0.0, 0.0, 1.0 }, /* blue */
750 { 0.0, 1.0, 0.0 }, /* green */
751 { 1.0, 0.0, 1.0 }, /* purple */
752 { 1.0, 0.4, 0.0 }, /* orange */
753 { 0.0, 1.0, 1.0 }, /* cyan */
754 { 1.0, 0.4, 0.4 }, /* pink */
755 { 1.0, 1.0, 0.0 }, /* yellow */
756 { 0.4, 0.4, 1.0 }, /* lightblue */
757 { 0.4, 1.0, 0.4 }, /* lightgreen */
758 { 1.0, 0.4, 1.0 }, /* lightpurple */
759 { 1.0, 0.7, 0.4 }, /* lightorange */
760 { 0.4, 1.0, 1.0 }, /* lightcyan */
761 { 0.0, 0.0, 0.0 } /* black */
766 *nlevel = std::min(16, *nlevel);
768 for (i = 0; (i < n); i++)
771 "\"%c%c c #%02X%02X%02X \" /* \"%3d\" */,\n",
772 mapper[(i + i0) % NMAP],
773 (n <= NMAP) ? ' ' : mapper[(i + i0) / NMAP],
774 static_cast<unsigned int>(round(255 * rgbd[i].r)),
775 static_cast<unsigned int>(round(255 * rgbd[i].g)),
776 static_cast<unsigned int>(round(255 * rgbd[i].b)),
782 static void write_xpm_map_split(FILE* out,
785 const int* nlevel_top,
790 gmx_bool bDiscreteColor,
799 ntot = *nlevel_top + *nlevel_bot;
802 gmx_fatal(FARGS, "Warning, too many levels (%d) in matrix", ntot);
805 fprintf(out, "static char *gromacs_xpm[] = {\n");
806 fprintf(out, "\"%d %d %d %d\",\n", n_x, n_y, ntot, 1);
810 pr_discrete_cmap(out, nlevel_bot, 0);
814 pr_simple_cmap(out, lo_bot, hi_bot, *nlevel_bot, rlo_bot, rhi_bot, 0);
817 pr_simple_cmap(out, lo_top, hi_top, *nlevel_top, rlo_top, rhi_top, *nlevel_bot);
821 static void write_xpm_map(FILE* out, int n_x, int n_y, int* nlevels, real lo, real hi, t_rgb rlo, t_rgb rhi)
824 real invlevel, r, g, b;
826 if (*nlevels > NMAP * NMAP)
829 "Warning, too many levels (%d) in matrix, using %d only\n",
831 static_cast<int>(NMAP * NMAP));
832 *nlevels = NMAP * NMAP;
834 else if (*nlevels < 2)
836 fprintf(stderr, "Warning, too few levels (%d) in matrix, using 2 instead\n", *nlevels);
840 fprintf(out, "static char *gromacs_xpm[] = {\n");
841 fprintf(out, "\"%d %d %d %d\",\n", n_x, n_y, *nlevels, (*nlevels <= NMAP) ? 1 : 2);
843 invlevel = 1.0 / (*nlevels - 1);
844 for (i = 0; (i < *nlevels); i++)
846 nlo = *nlevels - 1 - i;
847 r = (nlo * rlo.r + i * rhi.r) * invlevel;
848 g = (nlo * rlo.g + i * rhi.g) * invlevel;
849 b = (nlo * rlo.b + i * rhi.b) * invlevel;
851 "\"%c%c c #%02X%02X%02X \" /* \"%.3g\" */,\n",
853 (*nlevels <= NMAP) ? ' ' : mapper[i / NMAP],
854 static_cast<unsigned int>(std::round(255 * r)),
855 static_cast<unsigned int>(std::round(255 * g)),
856 static_cast<unsigned int>(std::round(255 * b)),
857 (nlo * lo + i * hi) * invlevel);
861 static void writeXpmAxis(FILE* out, const char* axis, ArrayRef<const real> label)
867 for (gmx::index i = 0; i != ssize(label); ++i)
873 fprintf(out, "*/\n");
875 fprintf(out, "/* %s-axis: ", axis);
877 fprintf(out, "%g ", label[i]);
879 fprintf(out, "*/\n");
882 static void write_xpm_data(FILE* out, int n_x, int n_y, real** mat, real lo, real hi, int nlevels)
887 invlevel = (nlevels - 1) / (hi - lo);
888 for (j = n_y - 1; (j >= 0); j--)
890 if (j % (1 + n_y / 100) == 0)
892 fprintf(stderr, "%3d%%\b\b\b\b", (100 * (n_y - j)) / n_y);
895 for (i = 0; (i < n_x); i++)
897 c = roundToInt((mat[i][j] - lo) * invlevel);
908 fprintf(out, "%c", mapper[c]);
912 fprintf(out, "%c%c", mapper[c % NMAP], mapper[c / NMAP]);
917 fprintf(out, "\",\n");
921 fprintf(out, "\"\n");
926 static void write_xpm_data3(FILE* out, int n_x, int n_y, real** mat, real lo, real mid, real hi, int nlevels)
928 int i, j, c = 0, nmid;
929 real invlev_lo, invlev_hi;
931 nmid = calc_nmid(nlevels, lo, mid, hi);
932 invlev_hi = (nlevels - 1 - nmid) / (hi - mid);
933 invlev_lo = (nmid) / (mid - lo);
935 for (j = n_y - 1; (j >= 0); j--)
937 if (j % (1 + n_y / 100) == 0)
939 fprintf(stderr, "%3d%%\b\b\b\b", (100 * (n_y - j)) / n_y);
942 for (i = 0; (i < n_x); i++)
944 if (mat[i][j] >= mid)
946 c = nmid + roundToInt((mat[i][j] - mid) * invlev_hi);
948 else if (mat[i][j] >= lo)
950 c = roundToInt((mat[i][j] - lo) * invlev_lo);
967 fprintf(out, "%c", mapper[c]);
971 fprintf(out, "%c%c", mapper[c % NMAP], mapper[c / NMAP]);
976 fprintf(out, "\",\n");
980 fprintf(out, "\"\n");
985 static void write_xpm_data_split(FILE* out,
997 real invlev_top, invlev_bot;
999 invlev_top = (nlevel_top - 1) / (hi_top - lo_top);
1000 invlev_bot = (nlevel_bot - 1) / (hi_bot - lo_bot);
1002 for (j = n_y - 1; (j >= 0); j--)
1004 if (j % (1 + n_y / 100) == 0)
1006 fprintf(stderr, "%3d%%\b\b\b\b", (100 * (n_y - j)) / n_y);
1009 for (i = 0; (i < n_x); i++)
1013 c = nlevel_bot + roundToInt((mat[i][j] - lo_top) * invlev_top);
1014 if ((c < nlevel_bot) || (c >= nlevel_bot + nlevel_top))
1017 "Range checking i = %d, j = %d, c = %d, bot = %d, top = %d "
1029 c = roundToInt((mat[i][j] - lo_bot) * invlev_bot);
1030 if ((c < 0) || (c >= nlevel_bot + nlevel_bot))
1033 "Range checking i = %d, j = %d, c = %d, bot = %d, top = %d "
1048 fprintf(out, "%c", mapper[c]);
1052 fprintf(out, "\",\n");
1056 fprintf(out, "\"\n");
1061 void write_xpm_m(FILE* out, t_matrix m)
1066 bOneChar = (m.map[0].code.c2 == 0);
1067 write_xpm_header(out, m.title, m.legend, m.label_x, m.label_y, m.bDiscrete);
1068 fprintf(out, "static char *gromacs_xpm[] = {\n");
1069 fprintf(out, "\"%d %d %zu %d\",\n", m.nx, m.ny, m.map.size(), bOneChar ? 1 : 2);
1070 for (const auto& map : m.map)
1073 "\"%c%c c #%02X%02X%02X \" /* \"%s\" */,\n",
1075 bOneChar ? ' ' : map.code.c2,
1076 static_cast<unsigned int>(round(map.rgb.r * 255)),
1077 static_cast<unsigned int>(round(map.rgb.g * 255)),
1078 static_cast<unsigned int>(round(map.rgb.b * 255)),
1081 writeXpmAxis(out, "x", m.axis_x);
1082 writeXpmAxis(out, "y", m.axis_y);
1083 for (int j = m.ny - 1; (j >= 0); j--)
1085 if (j % (1 + m.ny / 100) == 0)
1087 fprintf(stderr, "%3d%%\b\b\b\b", (100 * (m.ny - j)) / m.ny);
1092 for (int i = 0; (i < m.nx); i++)
1094 fprintf(out, "%c", m.map[m.matrix(i, j)].code.c1);
1099 for (int i = 0; (i < m.nx); i++)
1101 c = m.map[m.matrix(i, j)].code;
1102 fprintf(out, "%c%c", c.c1, c.c2);
1107 fprintf(out, "\",\n");
1111 fprintf(out, "\"\n");
1116 void write_xpm3(FILE* out,
1118 const std::string& title,
1119 const std::string& legend,
1120 const std::string& label_x,
1121 const std::string& label_y,
1136 * Writes a colormap varying as rlo -> rmid -> rhi.
1141 gmx_fatal(FARGS, "hi (%g) <= lo (%g)", hi, lo);
1144 write_xpm_header(out, title, legend, label_x, label_y, FALSE);
1145 write_xpm_map3(out, n_x, n_y, nlevels, lo, mid, hi, rlo, rmid, rhi);
1146 writeXpmAxis(out, "x", ArrayRef<real>(axis_x, axis_x + n_x + ((flags & MAT_SPATIAL_X) != 0U ? 1 : 0)));
1147 writeXpmAxis(out, "y", ArrayRef<real>(axis_y, axis_y + n_y + ((flags & MAT_SPATIAL_Y) != 0U ? 1 : 0)));
1148 write_xpm_data3(out, n_x, n_y, mat, lo, mid, hi, *nlevels);
1151 void write_xpm_split(FILE* out,
1153 const std::string& title,
1154 const std::string& legend,
1155 const std::string& label_x,
1156 const std::string& label_y,
1170 gmx_bool bDiscreteColor,
1175 * Writes a colormap varying as rlo -> rmid -> rhi.
1178 if (hi_top <= lo_top)
1180 gmx_fatal(FARGS, "hi_top (%g) <= lo_top (%g)", hi_top, lo_top);
1182 if (hi_bot <= lo_bot)
1184 gmx_fatal(FARGS, "hi_bot (%g) <= lo_bot (%g)", hi_bot, lo_bot);
1186 if (bDiscreteColor && (*nlevel_bot >= 16))
1188 gmx_impl("Can not plot more than 16 discrete colors");
1191 write_xpm_header(out, title, legend, label_x, label_y, FALSE);
1192 write_xpm_map_split(
1193 out, n_x, n_y, nlevel_top, lo_top, hi_top, rlo_top, rhi_top, bDiscreteColor, nlevel_bot, lo_bot, hi_bot, rlo_bot, rhi_bot);
1194 writeXpmAxis(out, "x", ArrayRef<real>(axis_x, axis_x + n_x + ((flags & MAT_SPATIAL_X) != 0U ? 1 : 0)));
1195 writeXpmAxis(out, "y", ArrayRef<real>(axis_y, axis_y + n_y + ((flags & MAT_SPATIAL_Y) != 0U ? 1 : 0)));
1196 write_xpm_data_split(out, n_x, n_y, mat, lo_top, hi_top, *nlevel_top, lo_bot, hi_bot, *nlevel_bot);
1199 void write_xpm(FILE* out,
1201 const std::string& title,
1202 const std::string& legend,
1203 const std::string& label_x,
1204 const std::string& label_y,
1217 * title matrix title
1218 * legend label for the continuous legend
1219 * label_x label for the x-axis
1220 * label_y label for the y-axis
1221 * n_x, n_y size of the matrix
1222 * axis_x[] the x-ticklabels
1223 * axis_y[] the y-ticklables
1224 * *matrix[] element x,y is matrix[x][y]
1225 * lo output lower than lo is set to lo
1226 * hi output higher than hi is set to hi
1227 * rlo rgb value for level lo
1228 * rhi rgb value for level hi
1229 * nlevels number of color levels for the output
1234 gmx_fatal(FARGS, "hi (%f) <= lo (%f)", hi, lo);
1237 write_xpm_header(out, title, legend, label_x, label_y, FALSE);
1238 write_xpm_map(out, n_x, n_y, nlevels, lo, hi, rlo, rhi);
1239 writeXpmAxis(out, "x", ArrayRef<real>(axis_x, axis_x + n_x + ((flags & MAT_SPATIAL_X) != 0U ? 1 : 0)));
1240 writeXpmAxis(out, "y", ArrayRef<real>(axis_y, axis_y + n_y + ((flags & MAT_SPATIAL_Y) != 0U ? 1 : 0)));
1241 write_xpm_data(out, n_x, n_y, mat, lo, hi, *nlevels);