C   8

emit.c

Guest on 20th July 2021 03:05:36 PM

  1. /* emit.c
  2.    Copyright (C)  Eugene K. Ressler, Jr.
  3.  
  4. This file is part of Sketch, a small, simple system for making
  5. 3d drawings with LaTeX and the PSTricks or TikZ package.
  6.  
  7. Sketch is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 3, or (at your option)
  10. any later version.
  11.  
  12. Sketch is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Sketch; see the file COPYING.txt.  If not, see
  19. http://www.gnu.org/copyleft */
  20.  
  21. #include <math.h>
  22. #include "emit.h"
  23. #include "scene.h"
  24. #include "version.h"
  25.  
  26. // ---- emit output -----------------------------------------------------------
  27.  
  28. char standard_us_doc_template_file_name_flag[] =
  29.   "<standard us doc template file name flag>";
  30. char standard_euro_doc_template_file_name_flag[] =
  31.   "<standard euro doc template file name flag>";
  32.  
  33. // concise floating point output
  34. // idea of %g but with fixed rather than relative precision
  35. // removing excessive 0's often reduces output file size dramatically
  36. // and also eases reading
  37. char *
  38. flt_str_fmt (char *fmt, char *buf, double f)
  39. {
  40.   size_t i;
  41.  
  42.   sprintf (buf, fmt, f);
  43.  
  44.   // trim off useless zeros and decimals
  45.   for (i = strlen (buf); i > 0 && buf[i - 1] == '0'; i--)
  46.     /* skip */ ;
  47.   if (i > 0 && buf[i - 1] == '.')
  48.     i--;
  49.   buf[i] = '\0';
  50.  
  51.   // remove leading zeros before decimal
  52.   if (buf[0] == '0' && buf[1] == '.')
  53.     for (i = 0; (buf[i] = buf[i + 1]) != '\0'; i++)
  54.       /* skip */ ;
  55.   else if (buf[0] == '-' && buf[1] == '0' && buf[2] == '.')
  56.     for (i = 1; (buf[i] = buf[i + 1]) != '\0'; i++)
  57.       /* skip */ ;
  58.  
  59.   // fix -0
  60.   if (strcmp (buf, "-0") == 0)
  61.     strcpy (buf, "0");
  62.  
  63.   return buf;
  64. }
  65.  
  66. char *
  67. flt_str (char *buf, double f)
  68. {
  69.   return flt_str_fmt ("%.3f", buf, f);
  70. }
  71.  
  72. // scan and return all the legal forms of special arg: ints, int range,
  73. // *arg_len is set to number of chars consumed by scanning even if there are range errors
  74. // return value is number of good arg indices scanned into *arg_index_1|2
  75. static int
  76. scan_special_arg (SPECIAL_OBJECT * special, int i,      // start index
  77.                   int *arg_len, // chars scanned
  78.                   int *arg_index_1,     // arg array indices (# - 1)
  79.                   int *arg_index_2, SRC_LINE line)      // line # for error messages
  80. {
  81.   int i1, i2, len, n_args, n_errs;
  82.  
  83.   // try two-arg cases and then one arg and then assume zero
  84.   if (sscanf (&special->code[i], "%d-%d%n", &i1, &i2, &len) >= 2 ||
  85.       sscanf (&special->code[i], "{%d-%d}%n", &i1, &i2, &len) >= 2)
  86.     {
  87.       *arg_len = len;
  88.       *arg_index_1 = i1 - 1;
  89.       *arg_index_2 = i2 - 1;
  90.       n_args = 2;
  91.     }
  92.   else if (sscanf (&special->code[i], "%d%n", &i1, &len) >= 1 ||
  93.            sscanf (&special->code[i], "{%d}%n", &i1, &len) >= 1)
  94.     {
  95.       *arg_len = len;
  96.       *arg_index_1 = i1 - 1;
  97.       n_args = 1;
  98.     }
  99.   else
  100.     {
  101.       *arg_len = 0;
  102.       n_args = 0;
  103.     }
  104.   n_errs = 0;
  105.   if (n_args >= 1 && (i1 < 1 || i1 > special->pts->n_pts))
  106.     {
  107.       err (line, "special arg #%d: out of range #[1-%d]", i1,
  108.            special->pts->n_pts);
  109.       ++n_errs;
  110.     }
  111.   if (n_args >= 2 && (i2 < 1 || i2 > special->pts->n_pts))
  112.     {
  113.       err (line, "special arg #n-%d: out of range #[1-%d]", i2,
  114.            special->pts->n_pts);
  115.       ++n_errs;
  116.     }
  117.   return n_errs > 0 ? 0 : n_args;
  118. }
  119.  
  120. // TikZ only does integer angles
  121. char *
  122. fmt_angle_tikz (char *buf, double theta, SRC_LINE line)
  123. {
  124.   int i_theta = (int) ((theta >= 0) ? (theta + 0.5) : (theta - 0.5));
  125.   double err = theta - i_theta;
  126.   if (fabs (err) >= 0.1)
  127.     warn (line, "TikZ angle rounding error is %.2 degrees", err);
  128.   return flt_str_fmt ("%1.f", buf, theta);
  129. }
  130.  
  131. char *
  132. fmt_angle_pst (char *buf, double theta, SRC_LINE line)
  133. {
  134.   return flt_str (buf, theta);
  135. }
  136.  
  137. typedef char *(*FMT_ANGLE_FUNC) (char *buf, double theta, SRC_LINE line);
  138.  
  139. FMT_ANGLE_FUNC fmt_angle_tbl[] = {
  140.   fmt_angle_pst,
  141.   fmt_angle_tikz,
  142.   fmt_angle_pst,
  143.   fmt_angle_tikz,
  144. };
  145.  
  146. // this parses, substitues, notes any errors, and (if f is set) prints special output
  147. // so it's used both for syntax checking during input and to generate output
  148. void
  149. process_special (FILE * f, SPECIAL_OBJECT * special, SRC_LINE line)
  150. {
  151.   char ch, buf1[16], buf2[16];
  152.   int i_arg_prev, i_arg, arg_len, arg_index_1, arg_index_2;
  153.  
  154.   i_arg_prev = i_arg = 0;
  155.   while ((ch = special->code[i_arg]) != '\0')
  156.     {
  157.       if (ch == '#')
  158.         {
  159.           if (special->code[i_arg + 1] == '#')
  160.             {
  161.               if (f)
  162.                 fprintf (f, "%.*s#",
  163.                          i_arg - i_arg_prev, &special->code[i_arg_prev]);
  164.               arg_len = 1;
  165.             }
  166.           else
  167.             {
  168.               switch (scan_special_arg
  169.                       (special, i_arg + 1, &arg_len, &arg_index_1,
  170.                        &arg_index_2, line))
  171.                 {
  172.                 case 2:
  173.                   if (f)
  174.                     fprintf (f, "%.*s{%s}", i_arg - i_arg_prev, // number of chars to write
  175.                              &special->code[i_arg_prev],        // start of chars
  176.                              (*fmt_angle_tbl
  177.                               [global_env->output_language])
  178.                              (buf1,
  179.                               180 / PI *
  180.                               atan2 (special->pts->v[arg_index_2][Y] -
  181.                                      special->pts->v[arg_index_1][Y],
  182.                                      special->pts->v[arg_index_2][X] -
  183.                                      special->pts->v[arg_index_1][X]), line));
  184.                   break;
  185.                 case 1:
  186.                   if (f)
  187.                     fprintf (f, "%.*s(%s,%s)", i_arg - i_arg_prev,      // number of chars to write
  188.                              &special->code[i_arg_prev],        // start of chars
  189.                              flt_str (buf1,
  190.                                       special->pts->v[arg_index_1][X]),
  191.                              flt_str (buf2, special->pts->v[arg_index_1][Y]));
  192.                   break;
  193.                 case 0:
  194.                   if (arg_len == 0)
  195.                     {           // couldn't scan an index at all
  196.                       if (f)
  197.                         fprintf (f, "%.*s#", i_arg - i_arg_prev,
  198.                                  &special->code[i_arg_prev]);
  199.                       warn (line,
  200.                             "use of '#' not as special arg (try ##)",
  201.                             arg_len, &special->code[i_arg]);
  202.                     }
  203.                   break;
  204.                 }
  205.             }
  206.           i_arg += (arg_len + 1);
  207.           i_arg_prev = i_arg;
  208.         }
  209.       else
  210.         {
  211.           ++i_arg;
  212.         }
  213.     }
  214.   // print out the last stretch of code
  215.   if (f)
  216.     fprintf (f, "%s\n", &special->code[i_arg_prev]);
  217. }
  218.  
  219. static void
  220. emit_points_pst (FILE * f, POINT_LIST_3D * pts)
  221. {
  222.   int i;
  223.   char buf1[16], buf2[16];
  224.  
  225.   for (i = 0; i < pts->n_pts; i++)
  226.     fprintf (f, "(%s,%s)",
  227.              flt_str (buf1, pts->v[i][X]), flt_str (buf2, pts->v[i][Y]));
  228. }
  229.  
  230. static void
  231. emit_dots_pst (FILE * f, OBJECT * obj)
  232. {
  233.   DOTS_OBJECT *dots = (DOTS_OBJECT *) obj;
  234.   fprintf (f, "\\psdots");
  235.   emit_opts (f, dots->opts, global_env->output_language);
  236.   emit_points_pst (f, dots->pts);
  237.   fprintf (f, "\n");
  238. }
  239.  
  240. static void
  241. emit_line_pst (FILE * f, OBJECT * obj)
  242. {
  243.   LINE_OBJECT *line = (LINE_OBJECT *) obj;
  244.   fprintf (f, "\\psline");
  245.   emit_opts (f, line->opts, global_env->output_language);
  246.   emit_points_pst (f, line->pts);
  247.   fprintf (f, "\n");
  248. }
  249.  
  250. static void
  251. emit_curve_pst (FILE * f, OBJECT * obj)
  252. {
  253.   CURVE_OBJECT *curve = (CURVE_OBJECT *) obj;
  254.   fprintf (f, "\\pscurve");
  255.   emit_opts (f, curve->opts, global_env->output_language);
  256.   emit_points_pst (f, curve->pts);
  257.   fprintf (f, "\n");
  258. }
  259.  
  260. static void
  261. emit_polygon_pst (FILE * f, OBJECT * obj)
  262. {
  263.   POLYGON_OBJECT *poly = (POLYGON_OBJECT *) obj;
  264.   fprintf (f, "\\pspolygon");
  265.   emit_opts (f, poly->opts, global_env->output_language);
  266.   emit_points_pst (f, poly->pts);
  267.   fprintf (f, "\n");
  268. }
  269.  
  270. static void
  271. emit_special_pst (FILE * f, OBJECT * obj)
  272. {
  273.   process_special (f, (SPECIAL_OBJECT *) obj, no_line);
  274. }
  275.  
  276. typedef void (*EMIT_FUNC) (FILE * f, OBJECT *);
  277.  
  278. static EMIT_FUNC emit_tbl_pst[] = {
  279.   NULL,                         // O_BASE
  280.   NULL,                         // O_TAG_DEF
  281.   NULL,                         // O_OPTS_DEF
  282.   NULL,                         // O_SCALAR_DEF
  283.   NULL,                         // O_POINT_DEF
  284.   NULL,                         // O_VECTOR_DEF
  285.   NULL,                         // O_TRANSFORM_DEF
  286.   emit_dots_pst,
  287.   emit_line_pst,
  288.   emit_curve_pst,
  289.   emit_polygon_pst,
  290.   emit_special_pst,
  291.   NULL,                         // O_SWEEP (flattened)
  292.   NULL,                         // O_REPEAT (flattened)
  293.   NULL,                         // O_COMPOUND (flattened)
  294. };
  295.  
  296. static void
  297. emit_points_tkz (FILE * f, POINT_LIST_3D * pts, char *twixt, char *final)
  298. {
  299.   int i;
  300.   char buf1[16], buf2[16];
  301.  
  302.   for (i = 0; i < pts->n_pts; i++)
  303.     fprintf (f, "(%s,%s)%s",
  304.              flt_str (buf1, pts->v[i][X]),
  305.              flt_str (buf2, pts->v[i][Y]),
  306.              (i == pts->n_pts - 1) ? final : twixt);
  307. }
  308.  
  309. static void
  310. emit_dots_tkz (FILE * f, OBJECT * obj)
  311. {
  312.   static char *skip[] = { "dotsize", NULL };
  313.   char *dotsize, *cmd;
  314.  
  315.   DOTS_OBJECT *dots = (DOTS_OBJECT *) obj;
  316.  
  317.   // An ugly hack because TikZ uses special syntax for circles...
  318.   dotsize = opt_val(dots->opts, "dotsize");
  319.   if (dotsize == NULL)
  320.     dotsize = "2pt";
  321.   cmd = safe_malloc(strlen(dotsize) + 100);
  322.   sprintf(cmd, " circle (%s)", dotsize);
  323.  
  324.   fprintf (f, "\\filldraw");
  325.   emit_opts_with_exceptions (f, dots->opts, skip, global_env->output_language);
  326.   emit_points_tkz (f, dots->pts, cmd, cmd);
  327.   fprintf (f, ";\n");
  328.  
  329.   safe_free(cmd);
  330. }
  331.  
  332. static void
  333. emit_line_tkz (FILE * f, OBJECT * obj)
  334. {
  335.   LINE_OBJECT *line = (LINE_OBJECT *) obj;
  336.   fprintf (f, "\\draw");
  337.   emit_opts (f, line->opts, global_env->output_language);
  338.   emit_points_tkz (f, line->pts, "--", "");
  339.   fprintf (f, ";\n");
  340. }
  341.  
  342. static void
  343. emit_curve_tkz (FILE * f, OBJECT * obj)
  344. {
  345.   CURVE_OBJECT *curve = (CURVE_OBJECT *) obj;
  346.   fprintf (f, "\\curve");
  347.   emit_opts (f, curve->opts, global_env->output_language);
  348.   emit_points_tkz (f, curve->pts, "--", "");
  349.   fprintf (f, ";\n");
  350. }
  351.  
  352. static void
  353. emit_polygon_tkz (FILE * f, OBJECT * obj)
  354. {
  355.   POLYGON_OBJECT *poly = (POLYGON_OBJECT *) obj;
  356.   fprintf (f, "\\filldraw");
  357.   emit_opts (f, poly->opts, global_env->output_language);
  358.   emit_points_tkz (f, poly->pts, "--", "--cycle");
  359.   fprintf (f, ";\n");
  360. }
  361.  
  362. static void
  363. emit_special_tkz (FILE * f, OBJECT * obj)
  364. {
  365.   process_special (f, (SPECIAL_OBJECT *) obj, no_line);
  366. }
  367.  
  368. static EMIT_FUNC emit_tbl_tkz[] = {
  369.   NULL,                         // O_BASE
  370.   NULL,                         // O_TAG_DEF
  371.   NULL,                         // O_OPTS_DEF
  372.   NULL,                         // O_SCALAR_DEF
  373.   NULL,                         // O_POINT_DEF
  374.   NULL,                         // O_VECTOR_DEF
  375.   NULL,                         // O_TRANSFORM_DEF
  376.   emit_dots_tkz,
  377.   emit_line_tkz,
  378.   emit_curve_tkz,
  379.   emit_polygon_tkz,
  380.   emit_special_tkz,
  381.   NULL,                         // O_SWEEP (flattened)
  382.   NULL,                         // O_REPEAT (flattened)
  383.   NULL,                         // O_COMPOUND (flattened)
  384. };
  385.  
  386. static EMIT_FUNC *emit_tbl_tbl[] = {
  387.   emit_tbl_pst,
  388.   emit_tbl_tkz,
  389.   emit_tbl_pst,
  390.   emit_tbl_tkz,
  391. };
  392.  
  393. #define DOC_TEMPLATE_ESCAPE_STRING "%%SKETCH_OUTPUT%%"
  394. #define DOC_TEMPLATE_ESCAPE_STRING_LEN (sizeof(DOC_TEMPLATE_ESCAPE_STRING) - 1)
  395.  
  396. char standard_us_doc_template_tikz_latex[] =
  397.   "\\documentclass[letterpaper,12pt]{article}\n"
  398.   "\\usepackage[x11names,rgb]{xcolor}\n"
  399.   "\\usepackage{tikz}\n"
  400.   "\\usetikzlibrary{snakes}\n"
  401.   "\\usetikzlibrary{arrows}\n"
  402.   "\\usetikzlibrary{shapes}\n"
  403.   "\\usetikzlibrary{backgrounds}\n"
  404.   "\\usepackage{amsmath}\n"
  405.   "\\oddsidemargin 0in\n"
  406.   "\\evensidemargin 0in\n"
  407.   "\\topmargin 0in\n"
  408.   "\\headheight 0in\n"
  409.   "\\headsep 0in\n"
  410.   "\\textheight 9in\n"
  411.   "\\textwidth 6.5in\n"
  412.   "\\begin{document}\n"
  413.   "\\pagestyle{empty}\n"
  414.   "\\vspace*{\\fill}\n"
  415.   "\\begin{center}\n"
  416.   DOC_TEMPLATE_ESCAPE_STRING "\n"
  417.   "\\end{center}\n" "\\vspace*{\\fill}\n" "\\end{document}\n";
  418.  
  419. char standard_euro_doc_template_tikz_latex[] =
  420.   "\\documentclass[a4paper,12pt]{article}\n"
  421.   "\\usepackage[x11names,rgb]{xcolor}\n"
  422.   "\\usepackage{tikz}\n"
  423.   "\\usetikzlibrary{snakes}\n"
  424.   "\\usetikzlibrary{arrows}\n"
  425.   "\\usetikzlibrary{shapes}\n"
  426.   "\\usetikzlibrary{backgrounds}\n"
  427.   "\\usepackage{amsmath}\n"
  428.   "\\oddsidemargin -10mm\n"
  429.   "\\evensidemargin -10mm\n"
  430.   "\\topmargin 5mm\n"
  431.   "\\headheight 0cm\n"
  432.   "\\headsep 0cm\n"
  433.   "\\textheight 247mm\n"
  434.   "\\textwidth 160mm\n"
  435.   "\\begin{document}\n"
  436.   "\\pagestyle{empty}\n"
  437.   "\\vspace*{\\fill}\n"
  438.   "\\begin{center}\n"
  439.   DOC_TEMPLATE_ESCAPE_STRING "\n"
  440.   "\\end{center}\n" "\\vspace*{\\fill}\n" "\\end{document}\n";
  441.  
  442. char standard_us_doc_template_pst_latex[] =
  443.   "\\documentclass[letterpaper,12pt]{article}\n"
  444.   "\\usepackage{amsmath}\n"
  445.   "\\usepackage{pstricks}\n"
  446.   "\\usepackage{pstricks-add}\n"
  447.   "\\oddsidemargin 0in\n"
  448.   "\\evensidemargin 0in\n"
  449.   "\\topmargin 0in\n"
  450.   "\\headheight 0in\n"
  451.   "\\headsep 0in\n"
  452.   "\\textheight 9in\n"
  453.   "\\textwidth 6.5in\n"
  454.   "\\begin{document}\n"
  455.   "\\pagestyle{empty}\n"
  456.   "\\vspace*{\\fill}\n"
  457.   "\\begin{center}\n"
  458.   DOC_TEMPLATE_ESCAPE_STRING "\n"
  459.   "\\end{center}\n" "\\vspace*{\\fill}\n" "\\end{document}\n";
  460.  
  461. char standard_euro_doc_template_pst_latex[] =
  462.   "\\documentclass[a4paper,12pt]{article}\n"
  463.   "\\usepackage{amsmath}\n"
  464.   "\\usepackage{pstricks}\n"
  465.   "\\usepackage{pstricks-add}\n"
  466.   "\\oddsidemargin -10mm\n"
  467.   "\\evensidemargin -10mm\n"
  468.   "\\topmargin 5mm\n"
  469.   "\\headheight 0cm\n"
  470.   "\\headsep 0cm\n"
  471.   "\\textheight 247mm\n"
  472.   "\\textwidth 160mm\n"
  473.   "\\begin{document}\n"
  474.   "\\pagestyle{empty}\n"
  475.   "\\vspace*{\\fill}\n"
  476.   "\\begin{center}\n"
  477.   DOC_TEMPLATE_ESCAPE_STRING "\n"
  478.   "\\end{center}\n" "\\vspace*{\\fill}\n" "\\end{document}\n";
  479.  
  480. /* ---------------------------------------------------------------------- */
  481.  
  482. char standard_us_doc_template_tikz_context[] =
  483.   "\\usemodule[tikz] \\usetikzlibrary[snakes,arrows,shapes,backgrounds]\n"
  484.   "\\setuppapersize[letter][letter]\n"
  485.   "\\setuplayout[topspace=0in,backspace=0in,header=0in,footer=0in,height=middle,width=middle]\n"
  486.   "\\setuppagenumbering[state=stop] % no page numbers\n"
  487.   "\\starttext\n"
  488.   "\\startalignment[middle]\n"
  489.   DOC_TEMPLATE_ESCAPE_STRING "\n"
  490.   "\\stopalignment\n"
  491.   "\\stoptext\n";
  492.  
  493. char standard_euro_doc_template_tikz_context[] =
  494.   "\\usemodule[tikz] \\usetikzlibrary[snakes,arrows,shapes,backgrounds]\n"
  495.   "\\setuppapersize[a4][a4]\n"
  496.   "\\setuplayout[topspace=0cm,backspace=0cm,header=0cm,footer=0cm,height=middle,width=middle]\n"
  497.   "\\setuppagenumbering[state=stop] % no page numbers\n"
  498.   "\\starttext\n"
  499.   "\\startalignment[middle]\n"
  500.   DOC_TEMPLATE_ESCAPE_STRING "\n"
  501.   "\\stopalignment\n"
  502.   "\\stoptext\n";
  503.  
  504. char standard_us_doc_template_pst_context[] =
  505.   "PSTricks does not work with ConTeXt as of 1 Feb 2008.\n";
  506.  
  507. char standard_euro_doc_template_pst_context[] =
  508.   "PSTricks does not work with ConTeXt as of 1 Feb 2008.\n";
  509.  
  510. char *standard_us_doc_template[] = {
  511.   standard_us_doc_template_pst_latex,
  512.   standard_us_doc_template_tikz_latex,
  513.   standard_us_doc_template_pst_context,
  514.   standard_us_doc_template_tikz_context,
  515. };
  516.  
  517. char *standard_euro_doc_template[] = {
  518.   standard_euro_doc_template_pst_latex,
  519.   standard_euro_doc_template_tikz_latex,
  520.   standard_euro_doc_template_pst_context,
  521.   standard_euro_doc_template_tikz_context,
  522. };
  523.  
  524. char *
  525. read_file_as_string (FILE * f)
  526. {
  527.   size_t len = 0;
  528.   int buf_size = 1024;
  529.   char *buf = safe_malloc (buf_size + 1);
  530.   for (;;)
  531.     {
  532.       len += fread (buf + len, 1, buf_size - len, f);
  533.       if (feof (f) || ferror (f))
  534.         {
  535.           buf[len] = '\0';
  536.           return buf;
  537.         }
  538.       buf_size *= 2;
  539.       buf = safe_realloc (buf, buf_size + 1);
  540.     }
  541. }
  542.  
  543. char *
  544. doc_template_from_file (char *file_name, int output_language)
  545. {
  546.   FILE *f;
  547.   char *r;
  548.  
  549.   if (file_name == NULL)
  550.     return NULL;
  551.   if (file_name == standard_us_doc_template_file_name_flag)
  552.     return safe_strdup (standard_us_doc_template[output_language]);
  553.   if (file_name == standard_euro_doc_template_file_name_flag)
  554.     return safe_strdup (standard_euro_doc_template[output_language]);
  555.  
  556.   f = fopen (file_name, "r");
  557.   if (!f)
  558.     {
  559.       err (no_line, "can't open document template '%s%' for input\n",
  560.            file_name);
  561.       return safe_strdup (standard_us_doc_template_pst_latex);
  562.     }
  563.   r = read_file_as_string (f);
  564.   fclose (f);
  565.   return r;
  566. }
  567.  
  568. void
  569. emit_preamble_pst_latex (FILE * f, BOX_3D * ext, GLOBAL_ENV * env)
  570. {
  571.   char buf1[16], buf2[16], buf3[16], buf4[16];
  572.  
  573.   if (global_env_is_set_p (env, GE_OPTS))
  574.     {
  575.       fprintf (f, "\\psset{");
  576.       emit_opts_raw (f, env->opts, global_env->output_language);
  577.       fprintf (f, "}\n");
  578.     }
  579.  
  580.   if (global_env_is_set_p (env, GE_FRAME))
  581.     {
  582.       if (env->frame_opts)
  583.         fprintf (f, "\\psframebox[%s]{", env->frame_opts);
  584.       else
  585.         fprintf (f, "\\psframebox[framesep=0pt]{");
  586.     }
  587.  
  588.   fprintf (f, "\\begin{pspicture%s}",
  589.            global_env_is_set_p (env, GE_EXTENT) ? "*" : "");
  590.  
  591.   if (global_env_is_set_p (env, GE_BASELINE))
  592.     fprintf (f, "[%s]", flt_str (buf1, env->baseline));
  593.  
  594.   fprintf (f,
  595.            "(%s,%s)(%s,%s)\n",
  596.            flt_str (buf1, ext->min[X]),
  597.            flt_str (buf2, ext->min[Y]),
  598.            flt_str (buf3, ext->max[X]), flt_str (buf4, ext->max[Y]));
  599.  
  600.   if (cmp_with_global_pst_version(env, STRINGIFY(PST_LINEJOIN_VERSION), no_line) < 0)
  601.     {
  602.       // old way to set linejoin
  603.       fprintf (f, "\\pstVerb{1 setlinejoin}\n");
  604.     }
  605.   else
  606.     {
  607.       fprintf (f,
  608.                "%% If your PSTricks is earlier than Version "
  609.                STRINGIFY(PST_LINEJOIN_VERSION) ", it will fail here.\n"
  610.                "%% Use sketch -V option for backward compatibility.\n"
  611.                "\\psset{linejoin=1}\n");
  612.     }
  613. }
  614.  
  615. void
  616. emit_preamble_tkz_latex (FILE * f, BOX_3D * ext, GLOBAL_ENV * env)
  617. {
  618.   char buf1[16], buf2[16], buf3[16], buf4[16];
  619.   int picture_opts_p = 0;
  620.  
  621.   if (global_env_is_set_p (env, GE_FRAME))
  622.     {
  623.       if (env->frame_opts)
  624.         warn (no_line, "frame options [%s] ignored (TikZ)", env->frame_opts);
  625.       else
  626.         {
  627.           fprintf (f, "{\\fboxsep=0pt\\fbox{");
  628.           warn (no_line,
  629.                 "remove frame around TikZ/PGF pictures for debugging");
  630.         }
  631.     }
  632.  
  633.   fprintf (f, "\\begin{tikzpicture}[join=round");
  634.   if (global_env_is_set_p (env, GE_OPTS))
  635.     {
  636.       fprintf (f, ",");
  637.       emit_opts_raw (f, env->opts, global_env->output_language);
  638.     }
  639.   if (global_env_is_set_p (env, GE_BASELINE))
  640.     {
  641.       fprintf (f, ",");
  642.       fprintf (f, "baseline=%s", flt_str (buf1, env->baseline));
  643.     }
  644.   fprintf (f, "]\n");
  645.   if (global_env_is_set_p (env, GE_EXTENT))
  646.     {
  647.       flt_str (buf1, ext->min[X]);
  648.       flt_str (buf2, ext->min[Y]);
  649.       flt_str (buf3, ext->max[X]);
  650.       flt_str (buf4, ext->max[Y]);
  651.       fprintf (f,
  652.                "\\useasboundingbox(%s,%s) rectangle (%s,%s);\n"
  653.                "\\clip(%s,%s) rectangle (%s,%s);\n",
  654.                buf1, buf2, buf3, buf4, buf1, buf2, buf3, buf4);
  655.     }
  656. }
  657.  
  658. // -----------------------------------------------------------------
  659.  
  660. void
  661. emit_preamble_pst_context (FILE * f, BOX_3D * ext, GLOBAL_ENV * env)
  662. {
  663.   char buf1[16], buf2[16], buf3[16], buf4[16];
  664.  
  665.   if (global_env_is_set_p (env, GE_OPTS))
  666.     {
  667.       fprintf (f, "\\psset{");
  668.       emit_opts_raw (f, env->opts, global_env->output_language);
  669.       fprintf (f, "}\n");
  670.     }
  671.  
  672.   fprintf (f,
  673.            "%% ConTeXt does not yet support PSTricks.\n"
  674.            "%% This is a guess at what the syntax might be.\n");
  675.  
  676.   if (global_env_is_set_p (env, GE_FRAME))
  677.     {
  678.       if (env->frame_opts)
  679.         fprintf (f, "\\psframebox[%s]{", env->frame_opts);
  680.       else
  681.         fprintf (f, "\\psframebox[framesep=0pt]{");
  682.     }
  683.  
  684.   fprintf (f, "\\startpspicture%s",
  685.            global_env_is_set_p (env, GE_EXTENT) ? "*" : "");
  686.  
  687.   if (global_env_is_set_p (env, GE_BASELINE))
  688.     fprintf (f, "[%s]", flt_str (buf1, env->baseline));
  689.  
  690.   fprintf (f,
  691.            "(%s,%s)(%s,%s)\n",
  692.            flt_str (buf1, ext->min[X]),
  693.            flt_str (buf2, ext->min[Y]),
  694.            flt_str (buf3, ext->max[X]), flt_str (buf4, ext->max[Y]));
  695.  
  696.   fprintf (f, "\\pstVerb{1 setlinejoin}\n");
  697. }
  698.  
  699. void
  700. emit_preamble_tkz_context (FILE * f, BOX_3D * ext, GLOBAL_ENV * env)
  701. {
  702.   char buf1[16], buf2[16], buf3[16], buf4[16];
  703.   int picture_opts_p = 0;
  704.  
  705.   if (global_env_is_set_p (env, GE_FRAME))
  706.     {
  707.       if (env->frame_opts)
  708.         warn (no_line, "frame options [%s] ignored (TikZ)", env->frame_opts);
  709.       else
  710.         {
  711.           fprintf (f, "{\\fboxsep=0pt\\fbox{");
  712.           warn (no_line,
  713.                 "remove frame around TikZ/PGF pictures for debugging");
  714.         }
  715.     }
  716.  
  717.   fprintf (f, "\\starttikzpicture[join=round");
  718.   if (global_env_is_set_p (env, GE_OPTS))
  719.     {
  720.       fprintf (f, ",");
  721.       emit_opts_raw (f, env->opts, global_env->output_language);
  722.     }
  723.   if (global_env_is_set_p (env, GE_BASELINE))
  724.     {
  725.       fprintf (f, ",");
  726.       fprintf (f, "baseline=%s", flt_str (buf1, env->baseline));
  727.     }
  728.   fprintf (f, "]\n");
  729.   if (global_env_is_set_p (env, GE_EXTENT))
  730.     {
  731.       flt_str (buf1, ext->min[X]);
  732.       flt_str (buf2, ext->min[Y]);
  733.       flt_str (buf3, ext->max[X]);
  734.       flt_str (buf4, ext->max[Y]);
  735.       fprintf (f,
  736.                "\\useasboundingbox(%s,%s) rectangle (%s,%s);\n"
  737.                "\\clip(%s,%s) rectangle (%s,%s);\n",
  738.                buf1, buf2, buf3, buf4, buf1, buf2, buf3, buf4);
  739.     }
  740. }
  741.  
  742. typedef void (*EMIT_PREAMBLE_FUNC) (FILE * f, BOX_3D * ext, GLOBAL_ENV * env);
  743.  
  744. EMIT_PREAMBLE_FUNC emit_preamble_tbl[] = {
  745.   emit_preamble_pst_latex,
  746.   emit_preamble_tkz_latex,
  747.   emit_preamble_pst_context,
  748.   emit_preamble_tkz_context,
  749. };
  750.  
  751. void
  752. emit_postamble_pst_latex (FILE * f, GLOBAL_ENV * env)
  753. {
  754.   fprintf (f, "\\end{pspicture%s}",
  755.            global_env_is_set_p (env, GE_EXTENT) ? "*" : "");
  756.   if (global_env_is_set_p (env, GE_FRAME))
  757.     fprintf (f, "}");
  758. }
  759.  
  760. void
  761. emit_postamble_tkz_latex (FILE * f, GLOBAL_ENV * env)
  762. {
  763.   fprintf (f, "\\end{tikzpicture}");
  764.   if (global_env_is_set_p (env, GE_FRAME))
  765.     fprintf (f, "}}");
  766. }
  767.  
  768. void
  769. emit_postamble_pst_context (FILE * f, GLOBAL_ENV * env)
  770. {
  771.   fprintf (f, "\\stoppspicture%s}",
  772.            global_env_is_set_p (env, GE_EXTENT) ? "*" : "");
  773.   if (global_env_is_set_p (env, GE_FRAME))
  774.     fprintf (f, "}");
  775. }
  776.  
  777. void
  778. emit_postamble_tkz_context (FILE * f, GLOBAL_ENV * env)
  779. {
  780.   fprintf (f, "\\stoptikzpicture");
  781.   if (global_env_is_set_p (env, GE_FRAME))
  782.     fprintf (f, "}}");
  783. }
  784.  
  785. typedef void (*EMIT_POSTAMBLE_FUNC) (FILE * f, GLOBAL_ENV * env);
  786.  
  787. EMIT_POSTAMBLE_FUNC emit_postamble_tbl[] = {
  788.   emit_postamble_pst_latex,
  789.   emit_postamble_tkz_latex,  
  790.   emit_postamble_pst_context,
  791.   emit_postamble_tkz_context,
  792. };
  793.  
  794. void
  795. emit (FILE * f, OBJECT * obj, GLOBAL_ENV * env, char *doc_template_file_name)
  796. {
  797.   BOX_3D ext[1];
  798.   int n_obj;
  799.   OBJECT *p;
  800.   char buf1[16], buf2[16], buf3[16], buf4[16];
  801.   char *escape, *doc_template;
  802.  
  803.   doc_template =
  804.     doc_template_from_file (doc_template_file_name, env->output_language);
  805.  
  806.   get_extent (obj, ext, &n_obj);
  807.   if (n_obj == 0)
  808.     err (no_line, "no objects to write");
  809.   else
  810.     {
  811.  
  812.       remark (no_line, "scene bb=(%s,%s)(%s,%s)",
  813.               flt_str (buf1, ext->min[X]),
  814.               flt_str (buf2, ext->min[Y]),
  815.               flt_str (buf3, ext->max[X]), flt_str (buf4, ext->max[Y]));
  816.  
  817.       if (get_transformed_global_env_extent (ext, env))
  818.         {
  819.           remark (no_line, "actual bb=(%s,%s)(%s,%s)",
  820.                   flt_str (buf1, ext->min[X]),
  821.                   flt_str (buf2, ext->min[Y]),
  822.                   flt_str (buf3, ext->max[X]), flt_str (buf4, ext->max[Y]));
  823.         }
  824.  
  825.       remark (no_line, "writing %d objects", n_obj);
  826.  
  827.       fprintf (f,
  828.                "%% Sketch output, version " VER_STRING "\n"
  829.                "%% Output language: %s\n",
  830.                output_language_str[env->output_language]);
  831.       escape = NULL;
  832.       if (doc_template)
  833.         {
  834.           escape = strstr (doc_template, DOC_TEMPLATE_ESCAPE_STRING);
  835.           if (escape)
  836.             fprintf (f, "%.*s", escape - doc_template, doc_template);
  837.           else
  838.             warn (no_line,
  839.                   "document template with no escape '%s' has been ignored",
  840.                   DOC_TEMPLATE_ESCAPE_STRING);
  841.         }
  842.  
  843.       (*emit_preamble_tbl[env->output_language]) (f, ext, env);
  844.  
  845.       for (p = obj; p; p = p->sibling)
  846.         {
  847.           if (emit_tbl_tbl[global_env->output_language][p->tag] == NULL)
  848.             die (no_line, "emit: bad tag %d", p->tag);
  849.           if (xy_overlap_p (p, ext))
  850.             (*emit_tbl_tbl[global_env->output_language][p->tag]) (f, p);
  851.         }
  852.  
  853.       (*emit_postamble_tbl[env->output_language]) (f, env);
  854.  
  855.       if (escape)
  856.         {
  857.           escape += DOC_TEMPLATE_ESCAPE_STRING_LEN;
  858.           fprintf (f, "%s", escape);
  859.           if (strstr (escape, DOC_TEMPLATE_ESCAPE_STRING))
  860.             warn (no_line,
  861.                   "more than one escape in document template; all but first ignored");
  862.         }
  863.       fprintf (f, "%% End sketch output\n");
  864.     }
  865. }

Raw Paste


Login or Register to edit or fork this paste. It's free.