10 #include "GmshConfig.h"
25 ret.assign(
"\\pgfplotsset{\ncolormap={gmshcolormap}{%% note: "
26 "Only needed once if colorbars do not change\n");
41 step = (double)(1. * ct->
size) / (samples - 1.);
45 for(
unsigned int j = 0; j < (
unsigned int)samples - 1; j++ ) {
46 idx = (
unsigned int)j * step;
53 Msg::Warning(
"PGF export does not handle transparent colormaps");
55 sprintf(tmp,
"rgb255=(%d,%d,%d) ", r, g, b);
67 sprintf(tmp,
"rgb255=(%d,%d,%d) ", r, g, b);
74 ret.append(
"}\n}%%\n");
80 const int samples, std::string &ret)
97 ret.assign(
"\tcolorbar style={\n\t\t%%width=0.5cm, "
98 "%% adjust width of colorbar\n"
99 "\t\t%%height=6cm,%% adjust height of colorbar,\n");
101 sprintf(tmp,
"\t\tsamples=%d,\n", samples + 1);
114 sprintf(tmp,
"\t\txticklabel={$10^{\\pgfmathparse{\\tick}"
115 "\\pgfmathprintnumber\\pgfmathresult}$},\n");
117 sprintf(tmp,
"\t\tyticklabel={$10^{\\pgfmathparse{\\tick}"
118 "\\pgfmathprintnumber\\pgfmathresult}$},\n");
122 ret.append(
"\t}]\n\t %% a dummy plot for the colorbar (invisible):\n");
124 cbmin = log10(cbmin);
125 cbmax = log10(cbmax);
129 "\t \\addplot[point meta min=%f,"
130 "point meta max=%f, update limits=false, draw=none, colorbar source]\n\t"
131 "coordinates{(1,1)};\n",
140 std::string post_var;
144 if(!post_var.empty()) {
145 sprintf(tmp,
"\ttitle={%s},\n", post_var.c_str());
148 ret.append(
"\tcolorbar,\n\tcolormap name=gmshcolormap,\n");
150 ret.append(
"\tcolorbar horizontal,\n");
153 ret.append(
"\tcolorbar right, %% or left...\n");
156 ret.append(
"\tcolorbar sampled,\n");
158 else if(intType == 1) {
159 ret.append(
"\tcolorbar sampled line,\n");
166 double xmin, xmax, ymin, ymax, zmin, zmax;
176 fprintf(stderr,
"General axes non auto, using\n");
177 fprintf(stderr,
"x=(%f,%f), y=(%f,%f), z=(%f,%f)\n", xmin, xmax, ymin, ymax,
188 fprintf(stderr,
"View axes non auto, using:\n");
189 fprintf(stderr,
"x=(%f,%f), y=(%f,%f), z=(%f,%f)\n", xmin, xmax, ymin, ymax,
199 fprintf(stderr,
"Axes auto, using:\n");
200 fprintf(stderr,
"x=(%f,%f), y=(%f,%f), z=(%f,%f)\n", xmin, xmax, ymin, ymax,
203 result[0][0] = result[1][0] = result[2][0] = result[3][0] = xmin;
204 result[4][0] = result[5][0] = result[6][0] = result[7][0] = xmax;
206 result[0][1] = result[1][1] = result[4][1] = result[5][1] = ymin;
207 result[2][1] = result[3][1] = result[6][1] = result[7][1] = ymax;
209 result[0][2] = result[2][2] = result[4][2] = result[6][2] = zmin;
210 result[1][2] = result[3][2] = result[5][2] = result[7][2] = zmax;
224 static int assemble2d(
const int num,
const int exportAxis, std::string &axisstr,
225 std::string &plotstr,
double *eulerAngles)
229 double xmin, xmax, ymin, ymax;
231 axisstr.append(
"\taxis equal image, %% use png aspect ratio\n");
235 std::string xlab, ylab, zlab;
239 if(xlab.empty()) xlab =
"x";
240 if(ylab.empty()) ylab =
"y";
241 if(zlab.empty()) zlab =
"z";
243 fprintf(stderr,
"Euler two dim: 0:%f, 1:%f, 2:%f\n", eulerAngles[0],
244 eulerAngles[1], eulerAngles[2]);
245 int r0 = (int)(eulerAngles[0] + 0.5);
246 int r1 = (int)(eulerAngles[1] + 0.5);
247 int r2 = (int)(eulerAngles[2] + 0.5);
248 if(r0 % 90 != 0 || r1 % 90 != 0 || r2 % 90 != 0) {
249 fprintf(stderr,
"Euler two dim: 0:%d, 1:%d, 2:%d\n", r0, r1, r2);
250 Msg::Error(
"Please select a plane view (X, Y, Z)");
253 if(r0 % 180 == 0 && r1 % 360 == 0 && r2 % 180 == 0) {
259 if(r2 == 180) axisstr.append(
"\tx dir=reverse,\n");
260 if((r2 == 180 && abs(r0) < 1) || (r0 == 180 && abs(r2) < 1))
261 axisstr.append(
"\ty dir=reverse,\n");
262 axisstr.append(
"\txlabel={" + xlab +
"},\n");
263 axisstr.append(
"\tylabel={" + ylab +
"},\n");
265 else if(r0 % 180 == 0 && r1 % 360 == 0 && (r2 == 90 || r2 == 270)) {
271 if(r2 == 90) axisstr.append(
"\tx dir=reverse,\n");
272 if(r2 == 270 || (r2 == 90 && r0 == 180))
273 axisstr.append(
"\ty dir=reverse,\n");
274 axisstr.append(
"\txlabel={" + ylab +
"},\n");
275 axisstr.append(
"\tylabel={" + xlab +
"},\n");
277 else if((r0 == 90 || r0 == 270) && r1 % 360 == 0 &&
278 (r2 == 90 || r2 == 270)) {
283 if(r2 == 90) axisstr.append(
"\tx dir=reverse,\n");
284 if(r0 == 90) axisstr.append(
"\ty dir=reverse,\n");
286 axisstr.append(
"\txlabel={" + ylab +
"},\n");
287 axisstr.append(
"\tylabel={" + zlab +
"},\n");
289 else if(r0 % 360 == 0 && (r1 == 90 || r1 == 270) && r2 % 180 == 0) {
295 if(r1 == 270) axisstr.append(
"\tx dir=reverse,\n");
296 if(r2 == 180) axisstr.append(
"\ty dir=reverse,\n");
297 axisstr.append(
"\txlabel={" + zlab +
"},\n");
298 axisstr.append(
"\tylabel={" + ylab +
"},\n");
300 else if((r0 == 90 || r0 == 270) && r1 % 360 == 0 && r2 % 180 == 0) {
307 axisstr.append(
"\tx dir=reverse,\n");
308 if(r0 == 90) axisstr.append(
"\ty dir=reverse,\n");
309 axisstr.append(
"\txlabel={" + xlab +
"},\n");
310 axisstr.append(
"\tylabel={" + zlab +
"},\n");
312 else if(r0 % 360 == 0 && (r1 == 90 || r1 == 270) &&
313 (r2 == 90 || r2 == 270)) {
314 if(r1 == 270) axisstr.append(
"\tx dir=reverse,\n");
315 if(r2 == 270) axisstr.append(
"\ty dir=reverse,\n");
321 axisstr.append(
"\txlabel={" + zlab +
"},\n");
322 axisstr.append(
"\tylabel={" + xlab +
"},\n");
325 Msg::Error(
"Cannot infer orientation from Euler angles...");
330 if(fabs(xmax - xmin) < 1e-8 || fabs(ymax - ymin) < 1e-8) {
332 "I inferred x (%f) or y (%f) dimension to be zero. Cannot produce.",
333 fabs(xmax - xmin), fabs(ymax - ymin));
337 double diagonal[3] = {xmax - xmin, ymax - ymin, 0};
338 double minlen =
norm3(diagonal);
342 suffix.assign(
" / $\\mu$m");
344 else if(minlen < 0.01) {
346 suffix.assign(
" / mm");
348 else if(minlen > 1e6) {
350 suffix.assign(
" / Mm");
352 else if(minlen > 1000) {
354 suffix.assign(
" / Km");
359 "The pgf output has been rescaled in order to please "
360 "the TeX number precision/range. Rescaling your results by "
367 std::size_t foundy = axisstr.rfind(
"},");
368 if(foundy != std::string::npos)
369 axisstr.insert(foundy, suffix);
373 std::size_t foundx = axisstr.rfind(
"},", foundy);
374 if(foundx != std::string::npos)
375 axisstr.insert(foundx, suffix);
380 axisstr.append(
"\tenlargelimits=false, %% tight axis, use xmin=<val>, ");
381 axisstr.append(
"xmax=<val> for custom bounding box\n");
382 axisstr.append(
"\taxis on top,\n\tscale only axis,\n");
386 xmin = 0, xmax = 1, ymin = 0, ymax = 1;
387 axisstr.append(
"\thide axis,\n");
390 sprintf(tmp,
"\t \\addplot graphics[xmin=%f, xmax=%f, ymin=%f, ymax=%f]\n",
391 xmin * factor, xmax * factor, ymin * factor, ymax * factor);
398 static int assemble3d(
const int num,
const int exportAxis, std::string &axisstr,
399 std::string &plotstr,
double *eulerAngles,
int *viewport,
400 double *proj,
double *model,
int ypix,
int xpix)
403 axisstr.append(
"\tenlargelimits=false, %% tight axis, use xmin=<val>, ");
404 axisstr.append(
"xmax=<val> for custom bounding box\n");
405 axisstr.append(
"\tgrid=both,\n\tminor tick num=1,\n");
406 std::string xlab, ylab, zlab;
410 if(xlab.empty()) xlab =
"x";
411 if(ylab.empty()) ylab =
"y";
412 if(zlab.empty()) zlab =
"z";
413 axisstr.append(
"\txlabel={" + xlab +
"}, %%\n\tylabel={" + ylab +
414 "},\n\tzlabel={" + zlab +
"},\n");
416 axisstr.append(
"\tzlabel style={rotate=-90},\n");
420 Msg::Warning(
"Axes are not orthogonal, but because you do not want "
421 "any axes, I'll continue with a 2d picture.");
422 return assemble2d(num, 0, axisstr, plotstr, eulerAngles);
425 Msg::Warning(
"Camera output not supported, but since you do not want "
426 "any axes, I'll continue with a 2d picture.");
427 return assemble2d(num, 0, axisstr, plotstr, eulerAngles);
429 axisstr.append(
"\thide axis,\n");
433 Msg::Warning(
"Cannot produce output if axes are not orthogonal.");
434 Msg::Error(
"Please switch to orthographic projection mode "
435 "('Alt + o') and retry if you want to output axes.");
444 double axViewPt[8][3];
445 std::vector<int> acceptableAnchors;
446 std::vector<int> masked;
448 bool reorder =
false;
451 for(
unsigned int j = 0; j < 8; j++) {
455 gluProject(axPts[j][0], axPts[j][1], axPts[j][2], model, proj, viewport,
456 &axViewPt[j][0], &axViewPt[j][1], &axViewPt[j][2]);
460 if((
int)(axViewPt[j][0] + 0.5) <= xpix &&
461 (
int)(axViewPt[j][1] + 0.5) <= ypix) {
462 acceptableAnchors.push_back(j);
468 minlen =
norm3(axPts[j]);
472 suffix.assign(
"/$\\mu$m");
474 else if(minlen < 0.01) {
476 suffix.assign(
"/mm");
478 else if(minlen > 1e6) {
480 suffix.assign(
"/Mm");
482 else if(minlen > 1000) {
484 suffix.assign(
"/Km");
487 if(j == 1 && acceptableAnchors.size() == 2) {
493 acceptableAnchors.pop_back();
496 if(reorder) acceptableAnchors.push_back(1);
498 if(acceptableAnchors.size() < 4) {
499 Msg::Error(
"Unable to calculate anchors for pgf output. "
500 "Make sure the entire scene is visible or adjust "
501 "the axes min/max values to fit inside your screen.");
507 "The pgf output has been rescaled in order to please "
508 "the TeX number precision/range. Rescaling your results by "
518 std::size_t foundrot = axisstr.rfind(
"},");
519 std::size_t foundz = axisstr.rfind(
"},", foundrot - 1);
520 if(foundz != std::string::npos)
521 axisstr.insert(foundz, suffix);
524 std::size_t foundy = axisstr.rfind(
"},", foundz);
525 if(foundy != std::string::npos)
526 axisstr.insert(foundy, suffix);
530 std::size_t foundx = axisstr.rfind(
"},", foundy);
531 if(foundx != std::string::npos)
532 axisstr.insert(foundx, suffix);
539 plotstr.assign(
"\t \\addplot3[surf] graphics[debug=false,%%=visual,\n");
540 plotstr.append(
"\t points={%%\n");
543 for(
auto it = acceptableAnchors.begin();
544 it != acceptableAnchors.end(); ++it, j++) {
545 sprintf(tmp,
"\t (%f,%f,%f)", factor * axPts[*it][0],
546 factor * axPts[*it][1], factor * axPts[*it][2]);
549 plotstr.append(
"%%");
552 sprintf(tmp,
" => (%d, %d-%d)\n", (
int)(axViewPt[*it][0] + 0.5), ypix,
553 ypix - (
int)(axViewPt[*it][1] + 0.5));
556 for(
auto it = masked.begin(); it != masked.end();
558 sprintf(tmp,
"\t (%f,%f,%f)", factor * axPts[*it][0],
559 factor * axPts[*it][1], factor * axPts[*it][2]);
561 plotstr.append(
" %% out of pixel range, discarded\n");
563 plotstr.append(
"\t }]\n");
567 int print_pgf(
const std::string &name,
const int num,
const int cnt,
568 PixelBuffer *buffer,
double *eulerAngles,
int *viewport,
569 double *proj,
double *model)
576 std::string pngfilen = path + base +
".png";
577 std::string pgffilen = path + base +
".pgf";
578 std::string texfilen = path + base +
".tex";
579 FILE *fp =
Fopen(pngfilen.c_str(),
"wb");
581 Msg::Error(
"Unable to open file '%s'", pngfilen.c_str());
591 Msg::Warning(
"PGF colorbar output works only with a single visible "
592 "scale. Consider disabling all but one. I can only create a "
593 "single colorbar. Colorbar will be suppressed");
596 std::string colmap_s, colbar_s, post_axis_s;
601 Msg::Error(
"Unable to assemble colormap for PGF output");
605 Msg::Error(
"Unable to assemble post processing axis for PGF output");
609 Msg::Error(
"Unable to assemble colorbar for PGF output");
614 colbar_s.assign(
"\t]\n");
617 std::string axis_s, plot_s;
618 axis_s.assign(
"\\begin{tikzpicture}\n\\begin{axis}[\n\twidth=.5\\linewidth,"
619 "%% set figure width here\n");
621 if(
assemble2d(num, exportAxis, axis_s, plot_s, eulerAngles) != 0) {
626 if(
assemble3d(num, exportAxis, axis_s, plot_s, eulerAngles, viewport, proj,
627 model, ypix, xpix) != 0) {
632 sprintf(tmp,
"\t {%s.png};\n", base.c_str());
635 fp =
Fopen(pgffilen.c_str(),
"wb");
637 Msg::Error(
"Unable to open file '%s'", pgffilen.c_str());
640 fprintf(fp,
"%s", colmap_s.c_str());
641 fprintf(fp,
"%s", axis_s.c_str());
642 fprintf(fp,
"%s", post_axis_s.c_str());
643 fprintf(fp,
"%s", colbar_s.c_str());
644 fprintf(fp,
"%s", plot_s.c_str());
645 fprintf(fp,
"\\end{axis}\n\\end{tikzpicture}%%\n");
651 if(system(
nullptr)) {
652 std::string pngname = name;
653 pngname.replace(pngname.end() - 3, pngname.end(),
"png");
654 sprintf(tmp,
"convert -trim %s %s", pngname.c_str(), pngname.c_str());
657 int ret = system(tmp);
658 Msg::Info(
"Conversion returned value %d", ret);
664 "One should now manually crop the margins, using e.g."
665 "gimp or `convert -trim %s %s` to get rid of any remaining"
667 pngfilen.c_str(), pngfilen.c_str());
674 "One should now manually crop the margins, using e.g."
675 "gimp or `convert -trim %s %s` to get rid of any remaining"
677 pngfilen.c_str(), pngfilen.c_str());
686 if(system(
nullptr)) {
687 std::string pngname = name;
688 pngname.replace(pngname.end() - 3, pngname.end(),
"png");
689 sprintf(tmp,
"convert -transparent white %s %s", pngname.c_str(),
693 int ret = system(tmp);
694 Msg::Info(
"Conversion returned value %d", ret);
696 Msg::Info(
"Automatic transparent white background successful.");
698 Msg::Warning(
"Cannot automatically add transparency to png.");
700 "One should now manually add a transparent layer in "
701 "order to not obstruct the axis. e.g. using gimp or "
702 "convert -transparent white %s %s`.",
703 pngfilen.c_str(), pngfilen.c_str());
708 Msg::Warning(
"Cannot automatically add transparency to output png.");
710 "One should now manually add a transparent layer in "
711 "order to not obstruct the axis. e.g. using gimp or "
712 "`convert -transparent white %s %s`.",
713 pngfilen.c_str(), pngfilen.c_str());
719 fp =
Fopen(texfilen.c_str(),
"r");
722 Msg::Info(
"File '%s' exists, please add '\\input{%s}' by yourself.",
723 texfilen.c_str(), pgffilen.c_str());
726 fp =
Fopen(texfilen.c_str(),
"w");
727 fprintf(fp,
"\\documentclass{article}\n\\usepackage{pgfplots}\n"
728 "\\pgfplotsset{compat=1.8}\n\\begin{document}\n");
729 fprintf(fp,
"\n\\input{%s}\n", pgffilen.c_str());
730 fprintf(fp,
"\n\\end{document}\n");