home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / groff / pic / tex.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-30  |  10.2 KB  |  411 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.uucp)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 1, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file LICENSE.  If not, write to the Free Software
  19. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. #ifdef TEX_SUPPORT
  22.  
  23. #include "pic.h"
  24. #include "common.h"
  25.  
  26. class tex_output : public common_output {
  27. public:
  28.   tex_output();
  29.   ~tex_output();
  30.   void start_picture(double, const position &ll, const position &ur);
  31.   void finish_picture();
  32.   void text(const position &, text_piece *, int, double);
  33.   void line(const position &, const position *, int n,
  34.         const line_type &);
  35.   void polygon(const position *, int n,
  36.            const line_type &, double);
  37.   void spline(const position &, const position *, int n,
  38.           const line_type &);
  39.   void arc(const position &, const position &, const position &,
  40.        const line_type &);
  41.   void circle(const position &, double rad, const line_type &, double);
  42.   void ellipse(const position &, const distance &, const line_type &, double);
  43.   void command(const char *, const char *, int);
  44.   int supports_filled_polygons();
  45. private:
  46.   position upper_left;
  47.   double height;
  48.   double width;
  49.   double scale;
  50.   double pen_size;
  51.  
  52.   void point(const position &);
  53.   void dot(const position &, const line_type &);
  54.   void solid_arc(const position ¢, double rad, double start_angle,
  55.          double end_angle, const line_type <);
  56.   position transform(const position &);
  57. protected:
  58.   virtual void set_pen_size(double ps);
  59. };
  60.  
  61. // convert inches to milliinches
  62.  
  63. inline int milliinches(double x)
  64. {
  65.   return int(x*1000.0 + .5);
  66. }
  67.  
  68. inline position tex_output::transform(const position &pos)
  69. {
  70.   return position((pos.x - upper_left.x)/scale,
  71.           (upper_left.y - pos.y)/scale);
  72. }
  73.  
  74. output *make_tex_output()
  75. {
  76.   return new tex_output;
  77. }
  78.  
  79. tex_output::tex_output()
  80. {
  81. }
  82.  
  83. tex_output::~tex_output()
  84. {
  85. }
  86.  
  87. const int DEFAULT_PEN_SIZE = 8;
  88.  
  89. void tex_output::set_pen_size(double ps)
  90. {
  91.   if (ps < 0.0)
  92.     ps = -1.0;
  93.   if (ps != pen_size) {
  94.     pen_size = ps;
  95.     printf("    \\special{pn %d}%%\n", 
  96.        ps < 0.0 ? DEFAULT_PEN_SIZE : int(ps*(1000.0/72.0) + .5));
  97.   }
  98. }
  99.  
  100. void tex_output::start_picture(double sc, const position &ll,
  101.                    const position &ur)
  102. {
  103.   upper_left.x = ll.x;
  104.   upper_left.y = ur.y;
  105.   scale = compute_scale(sc, ll, ur);
  106.   height = (ur.y - ll.y)/scale;
  107.   width = (ur.x - ll.x)/scale;
  108.   /* the point of \vskip 0pt is to ensure that the vtop gets
  109.     a height of 0 rather than the height of the hbox; this
  110.     might be non-zero if text from text attributes lies outside pic's
  111.     idea of the bounding box of the picture. */
  112.   fputs("\\expandafter\\ifx\\csname graph\\endcsname\\relax \\csname newbox\\endcsname\\graph\\fi\n"
  113.     "\\expandafter\\ifx\\csname graphtemp\\endcsname\\relax \\csname newdimen\\endcsname\\graphtemp\\fi\n"
  114.     "\\setbox\\graph=\\vtop{\\vskip 0pt\\hbox{%\n",
  115.     stdout);
  116.   pen_size = -2.0;
  117. }
  118.  
  119. void tex_output::finish_picture()
  120. {
  121.   printf("    \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n"
  122.      "    \\kern %.3fin\n"
  123.      "  }%%\n"
  124.      "}%%\n",
  125.      height, width);
  126. }
  127.  
  128. void tex_output::text(const position ¢er, text_piece *v, int n, double)
  129. {
  130.   position c = transform(center);
  131.   for (int i = 0; i < n; i++)
  132.     if (v[i].text != 0 && *v[i].text != '\0') {
  133.       int j = 2*i - n + 1;
  134.       if (v[i].adj.v == ABOVE_ADJUST)
  135.     j--;
  136.       else if (v[i].adj.v == BELOW_ADJUST)
  137.     j++;
  138.       if (j == 0) {
  139.     printf("    \\graphtemp=.5ex\\advance\\graphtemp by %.3fin\n", c.y);
  140.       }
  141.       else {
  142.     printf("    \\graphtemp=\\baselineskip"
  143.            "\\multiply\\graphtemp by %d"
  144.            "\\divide\\graphtemp by 2\n"
  145.            "    \\advance\\graphtemp by .5ex"
  146.            "\\advance\\graphtemp by %.3fin\n",
  147.            j, c.y);
  148.       }
  149.       printf("    \\rlap{\\kern %.3fin\\lower\\graphtemp", c.x);
  150.       fputs("\\hbox to 0pt{", stdout);
  151.       if (v[i].adj.h != LEFT_ADJUST)
  152.     fputs("\\hss ", stdout);
  153.       fputs(v[i].text, stdout);
  154.       if (v[i].adj.h != RIGHT_ADJUST)
  155.     fputs("\\hss", stdout);
  156.       fputs("}}%\n", stdout);
  157.     }
  158. }
  159.  
  160. void tex_output::point(const position &pos)
  161. {
  162.   position p = transform(pos);
  163.   printf("    \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y));
  164. }
  165.  
  166. void tex_output::line(const position &start, const position *v, int n,
  167.               const line_type <)
  168. {
  169.   set_pen_size(lt.thickness);
  170.   point(start);
  171.   for (int i = 0; i < n; i++)
  172.     point(v[i]);
  173.   fputs("    \\special{", stdout);
  174.   switch(lt.type) {
  175.   case line_type::invisible:
  176.     fputs("ip", stdout);
  177.     break;
  178.   case line_type::solid:
  179.     fputs("fp", stdout);
  180.     break;
  181.   case line_type::dotted:
  182.     printf("dt %.3f", lt.dash_width/scale);
  183.     break;
  184.   case line_type::dashed:
  185.     printf("da %.3f", lt.dash_width/scale);
  186.     break;
  187.   }
  188.   fputs("}%\n", stdout);
  189. }
  190.  
  191. void tex_output::polygon(const position *v, int n,
  192.              const line_type <, double fill)
  193. {
  194.   if (fill >= 0.0) {
  195.     if (fill > 1.0)
  196.       fill = 1.0;
  197.     printf("    \\special{sh %.3f}%%\n", fill);
  198.   }
  199.   line(v[n-1], v, n, lt);
  200. }
  201.  
  202. void tex_output::spline(const position &start, const position *v, int n,
  203.             const line_type <)
  204. {
  205.   if (lt.type == line_type::invisible)
  206.     return;
  207.   set_pen_size(lt.thickness);
  208.   point(start);
  209.   for (int i = 0; i < n; i++)
  210.     point(v[i]);
  211.   fputs("    \\special{sp", stdout);
  212.   switch(lt.type) {
  213.   case line_type::solid:
  214.     break;
  215.   case line_type::dotted:
  216.     printf(" %.3f", -lt.dash_width/scale);
  217.     break;
  218.   case line_type::dashed:
  219.     printf(" %.3f", lt.dash_width/scale);
  220.     break;
  221.   case line_type::invisible:
  222.     assert(0);
  223.   }
  224.   fputs("}%\n", stdout);
  225. }
  226.  
  227. void tex_output::solid_arc(const position ¢, double rad,
  228.                double start_angle, double end_angle,
  229.                const line_type <)
  230. {
  231.   set_pen_size(lt.thickness);
  232.   position c = transform(cent);
  233.   printf("    \\special{ar %d %d %d %d %f %f}%%\n",
  234.      milliinches(c.x),
  235.      milliinches(c.y),
  236.      milliinches(rad/scale),
  237.      milliinches(rad/scale),
  238.      -end_angle,
  239.      (-end_angle > -start_angle) ? M_PI * 2 - start_angle : -start_angle);
  240. }
  241.   
  242. void tex_output::arc(const position &start, const position ¢,
  243.              const position &end, const line_type <)
  244. {
  245.   switch (lt.type) {
  246.   case line_type::invisible:
  247.     break;
  248.   case line_type::dashed:
  249.     dashed_arc(start, cent, end, lt);
  250.     break;
  251.   case line_type::dotted:
  252.     dotted_arc(start, cent, end, lt);
  253.     break;
  254.   case line_type::solid:
  255.     {
  256.       position c;
  257.       if (!compute_arc_center(start, cent, end, &c)) {
  258.     line(start, &end, 1, lt);
  259.     break;
  260.       }
  261.       solid_arc(c,
  262.         hypot(cent - start),
  263.         atan2(start.y - c.y, start.x - c.x),
  264.         atan2(end.y - c.y, end.x - c.x),
  265.         lt);
  266.       break;
  267.     }
  268.   }
  269. }
  270.  
  271. void tex_output::circle(const position ¢, double rad,
  272.             const line_type <, double fill)
  273. {
  274.   if (fill >= 0.0 && lt.type != line_type::solid) {
  275.     if (fill > 1.0)
  276.       fill = 1.0;
  277.     line_type ilt;
  278.     ilt.type = line_type::invisible;
  279.     ellipse(cent, position(rad*2.0, rad*2.0), ilt, fill);
  280.   }
  281.   switch (lt.type) {
  282.   case line_type::dashed:
  283.     dashed_circle(cent, rad, lt);
  284.     break;
  285.   case line_type::invisible:
  286.     break;
  287.   case line_type::solid:
  288.     ellipse(cent, position(rad*2.0,rad*2.0), lt, fill);
  289.     break;
  290.   case line_type::dotted:
  291.     dotted_circle(cent, rad, lt);
  292.     break;
  293.   default:
  294.     assert(0);
  295.   }
  296. }
  297.  
  298. void tex_output::ellipse(const position ¢, const distance &dim,
  299.              const line_type <, double fill)
  300. {
  301.   if (lt.type == line_type::invisible) {
  302.     if (fill < 0.0)
  303.       return;
  304.   }
  305.   else
  306.     set_pen_size(lt.thickness);
  307.   if (fill >= 0.0) {
  308.     if (fill > 1.0)
  309.       fill = 1.0;
  310.     printf("    \\special{sh %.3f}%%\n", fill);
  311.   }
  312.   position c = transform(cent);
  313.   printf("    \\special{%s %d %d %d %d 0 6.28319}%%\n",
  314.      (lt.type == line_type::invisible ? "ia" : "ar"),
  315.      milliinches(c.x),
  316.      milliinches(c.y),
  317.      milliinches(dim.x/(2.0*scale)),
  318.      milliinches(dim.y/(2.0*scale)));
  319. }
  320.  
  321. void tex_output::command(const char *s, const char *, int)
  322. {
  323.   fputs(s, stdout);
  324.   putchar('%');            // avoid unwanted spaces
  325.   putchar('\n');
  326. }
  327.  
  328. int tex_output::supports_filled_polygons()
  329. {
  330.   return 1;
  331. }
  332.  
  333. void tex_output::dot(const position &pos, const line_type <)
  334. {
  335.   if (zero_length_line_flag) {
  336.     line_type slt = lt;
  337.     slt.type = line_type::solid;
  338.     line(pos, &pos, 1, slt);
  339.   }
  340.   else {
  341.     int dot_rad = int(lt.thickness*(1000.0/(72.0*2)) + .5);
  342.     if (dot_rad == 0)
  343.       dot_rad = 1;
  344.     position p = transform(pos);
  345.     printf("    \\special{sh 1}%%\n"
  346.        "    \\special{ia %d %d %d %d 0 6.28319}%%\n",
  347.        milliinches(p.x), milliinches(p.y), dot_rad, dot_rad);
  348.   }
  349. }
  350.  
  351. class tpic_output : public tex_output {
  352. public:
  353.   tpic_output();
  354.   void command(const char *, const char *, int);
  355. private:
  356.   void set_pen_size(double ps);
  357.   int default_pen_size;
  358.   int prev_default_pen_size;
  359. };
  360.  
  361. tpic_output::tpic_output()
  362. : default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE)
  363. {
  364. }
  365.  
  366. void tpic_output::command(const char *s, const char *filename, int lineno)
  367. {
  368.   assert(s[0] == '.');
  369.   if (s[1] == 'p' && s[2] == 's' && (s[3] == '\0' || !csalpha(s[3]))) {
  370.     const char *p = s + 3;
  371.     while (csspace(*p))
  372.       p++;
  373.     if (*p == '\0') {
  374.       int temp = default_pen_size;
  375.       default_pen_size = prev_default_pen_size;
  376.       prev_default_pen_size = temp;
  377.     }
  378.     else {
  379.       char *ptr;
  380.       int temp = (int)strtol(p, &ptr, 10);
  381.       if (temp == 0 && ptr == p)
  382.     error_with_file_and_line(filename, lineno,
  383.                  "argument to `.ps' not an integer");
  384.       else if (temp < 0)
  385.     error_with_file_and_line(filename, lineno,
  386.                  "negative pen size");
  387.       else {
  388.     prev_default_pen_size = default_pen_size;
  389.     default_pen_size = temp;
  390.       }
  391.     }
  392.   }
  393.   else
  394.     printf("\\%s%%\n", s + 1);
  395. }
  396.  
  397. void tpic_output::set_pen_size(double ps)
  398. {
  399.   if (ps < 0.0)
  400.     printf("    \\special{pn %d}%%\n", default_pen_size);
  401.   else
  402.     tex_output::set_pen_size(ps);
  403. }
  404.  
  405. output *make_tpic_output()
  406. {
  407.   return new tpic_output;
  408. }
  409.  
  410. #endif
  411.