home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / groff-1.09-src.lha / src / amiga / groff-1.09 / pic / tex.cc < prev    next >
C/C++ Source or Header  |  1992-08-03  |  10KB  |  412 lines

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