home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / groff / pic / troff.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-30  |  13.0 KB  |  525 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. #include "pic.h"
  22. #include "common.h"
  23.  
  24. const double RELATIVE_THICKNESS = -1.0;
  25. const double BAD_THICKNESS = -2.0;
  26.  
  27. class simple_output : public common_output {
  28.   virtual void simple_line(const position &, const position &) = 0;
  29.   virtual void simple_spline(const position &, const position *, int n) = 0;
  30.   virtual void simple_arc(const position &, const position &,
  31.               const position &) = 0;
  32.   virtual void simple_circle(int, const position &, double rad) = 0;
  33.   virtual void simple_ellipse(int, const position &, const distance &) = 0;
  34.   virtual void simple_polygon(int, const position *, int) = 0;
  35.   virtual void line_thickness(double) = 0;
  36.   virtual void set_fill(double) = 0;
  37.   void dot(const position &, const line_type &) = 0;
  38. public:
  39.   void start_picture(double sc, const position &ll, const position &ur) = 0;
  40.   void finish_picture() = 0;
  41.   void text(const position &, text_piece *, int, double) = 0;
  42.   void line(const position &, const position *, int n,
  43.         const line_type &);
  44.   void polygon(const position *, int n,
  45.            const line_type &, double);
  46.   void spline(const position &, const position *, int n,
  47.           const line_type &);
  48.   void arc(const position &, const position &, const position &,
  49.        const line_type &);
  50.   void circle(const position &, double rad, const line_type &, double);
  51.   void ellipse(const position &, const distance &, const line_type &, double);
  52.   int supports_filled_polygons();
  53. };
  54.  
  55. int simple_output::supports_filled_polygons()
  56. {
  57.   return driver_extension_flag != 0;
  58. }
  59.  
  60. void simple_output::arc(const position &start, const position ¢,
  61.             const position &end, const line_type <)
  62. {
  63.   switch (lt.type) {
  64.   case line_type::solid:
  65.     line_thickness(lt.thickness);
  66.     simple_arc(start, cent, end);
  67.     break;
  68.   case line_type::invisible:
  69.     break;
  70.   case line_type::dashed:
  71.     dashed_arc(start, cent, end, lt);
  72.     break;
  73.   case line_type::dotted:
  74.     dotted_arc(start, cent, end, lt);
  75.     break;
  76.   }
  77. }
  78.  
  79. void simple_output::line(const position &start, const position *v, int n,
  80.              const line_type <)
  81. {
  82.   position pos = start;
  83.   line_thickness(lt.thickness);
  84.   for (int i = 0; i < n; i++) {
  85.     switch (lt.type) {
  86.     case line_type::solid:
  87.       simple_line(pos, v[i]);
  88.       break;
  89.     case line_type::dotted:
  90.       {
  91.     distance vec(v[i] - pos);
  92.     double dist = hypot(vec);
  93.     int ndots = int(dist/lt.dash_width + .5);
  94.     if (ndots == 0)
  95.       dot(pos, lt);
  96.     else {
  97.       vec /= double(ndots);
  98.       for (int j = 0; j <= ndots; j++)
  99.         dot(pos + vec*j, lt);
  100.     }
  101.       }
  102.       break;
  103.     case line_type::dashed:
  104.       {
  105.     distance vec(v[i] - pos);
  106.     double dist = hypot(vec);
  107.     if (dist <= lt.dash_width*2.0)
  108.       simple_line(pos, v[i]);
  109.     else {
  110.       int ndashes = int((dist - lt.dash_width)/(lt.dash_width*2.0) + .5);
  111.       distance dash_vec = vec*(lt.dash_width/dist);
  112.       double dash_gap = (dist - lt.dash_width)/ndashes;
  113.       distance dash_gap_vec = vec*(dash_gap/dist);
  114.       for (int j = 0; j <= ndashes; j++) {
  115.         position s(pos + dash_gap_vec*j);
  116.         simple_line(s, s + dash_vec);
  117.       }
  118.     }
  119.       }
  120.       break;
  121.     case line_type::invisible:
  122.       break;
  123.     default:
  124.       assert(0);
  125.     }
  126.     pos = v[i];
  127.   }
  128. }
  129.  
  130. void simple_output::spline(const position &start, const position *v, int n,
  131.                const line_type <)
  132. {
  133.   line_thickness(lt.thickness);
  134.   simple_spline(start, v, n);
  135. }
  136.  
  137. void simple_output::polygon(const position *v, int n,
  138.                 const line_type <, double fill)
  139. {
  140.   if (driver_extension_flag) {
  141.     if (fill >= 0.0) {
  142.       set_fill(fill);
  143.       simple_polygon(1, v, n);
  144.     }
  145.   }
  146.   if (lt.type == line_type::solid && driver_extension_flag) {
  147.     line_thickness(lt.thickness);
  148.     simple_polygon(0, v, n);
  149.   }
  150.   else if (lt.type != line_type::invisible) {
  151.     line_thickness(lt.thickness);
  152.     line(v[n - 1], v, n, lt);
  153.   }
  154. }
  155.  
  156. void simple_output::circle(const position ¢, double rad,
  157.                const line_type <, double fill)
  158. {
  159.   if (driver_extension_flag && fill >= 0.0) {
  160.     set_fill(fill);
  161.     simple_circle(1, cent, rad);
  162.   }
  163.   line_thickness(lt.thickness);
  164.   switch (lt.type) {
  165.   case line_type::invisible:
  166.     break;
  167.   case line_type::dashed:
  168.     dashed_circle(cent, rad, lt);
  169.     break;
  170.   case line_type::dotted:
  171.     dotted_circle(cent, rad, lt);
  172.     break;
  173.   case line_type::solid:
  174.     simple_circle(0, cent, rad);
  175.     break;
  176.   default:
  177.     assert(0);
  178.   }
  179. }
  180.  
  181. void simple_output::ellipse(const position ¢, const distance &dim,
  182.                 const line_type <, double fill)
  183. {
  184.   if (driver_extension_flag && fill >= 0.0) {
  185.     set_fill(fill);
  186.     simple_ellipse(1, cent, dim);
  187.   }
  188.   if (lt.type != line_type::invisible)
  189.     line_thickness(lt.thickness);
  190.   switch (lt.type) {
  191.   case line_type::invisible:
  192.     break;
  193.   case line_type::dotted:
  194.   case line_type::dashed:
  195.   case line_type::solid:
  196.     simple_ellipse(0, cent, dim);
  197.     break;
  198.   default:
  199.     assert(0);
  200.   }
  201. }
  202.  
  203. #define FILL_MAX 1000
  204.  
  205. class troff_output : public simple_output {
  206.   const char *last_filename;
  207.   position upper_left;
  208.   double height;
  209.   double scale;
  210.   double last_line_thickness;
  211.   double last_fill;
  212. public:
  213.   troff_output();
  214.   ~troff_output();
  215.   void start_picture(double, const position &ll, const position &ur);
  216.   void finish_picture();
  217.   void text(const position &, text_piece *, int, double);
  218.   void dot(const position &, const line_type &);
  219.   void command(const char *, const char *, int);
  220.   void set_location(const char *, int);
  221.   void simple_line(const position &, const position &);
  222.   void simple_spline(const position &, const position *, int n);
  223.   void simple_arc(const position &, const position &, const position &);
  224.   void simple_circle(int, const position &, double rad);
  225.   void simple_ellipse(int, const position &, const distance &);
  226.   void simple_polygon(int, const position *, int);
  227.   void line_thickness(double p);
  228.   void set_fill(double);
  229.   position transform(const position &);
  230. };
  231.  
  232. output *make_troff_output()
  233. {
  234.   return new troff_output;
  235. }
  236.  
  237. troff_output::troff_output()
  238. : last_filename(0), last_line_thickness(BAD_THICKNESS), last_fill(-1.0)
  239. {
  240. }
  241.  
  242. troff_output::~troff_output()
  243. {
  244. }
  245.  
  246. inline position troff_output::transform(const position &pos)
  247. {
  248.   return position((pos.x - upper_left.x)/scale,
  249.           (upper_left.y - pos.y)/scale);
  250. }
  251.  
  252. #define FILL_REG "00"
  253.  
  254. // if this register is defined, geqn won't produce `\x's
  255. #define EQN_NO_EXTRA_SPACE_REG "0x"
  256.  
  257. void troff_output::start_picture(double sc,
  258.                  const position &ll, const position &ur)
  259. {
  260.   upper_left.x = ll.x;
  261.   upper_left.y = ur.y;
  262.   scale = compute_scale(sc, ll, ur);
  263.   height = (ur.y - ll.y)/scale;
  264.   double width = (ur.x - ll.x)/scale;
  265.   printf(".PS %.3fi %.3fi", height, width);
  266.   if (args)
  267.     printf(" %s\n", args);
  268.   else
  269.     putchar('\n');
  270.   printf(".\\\" %g %g %g %g\n", ll.x, ll.y, ur.x, ur.y);
  271.   printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height, width, 0.0);
  272.   printf(".nr " FILL_REG " \\n(.u\n.nf\n");
  273.   printf(".nr " EQN_NO_EXTRA_SPACE_REG " 1\n");
  274. }
  275.  
  276. void troff_output::finish_picture()
  277. {
  278.   line_thickness(BAD_THICKNESS);
  279.   last_fill = -1.0;        // force it to be reset for each picture
  280.   if (!flyback_flag)
  281.     printf(".sp %.3fi+1\n", height);
  282.   printf(".if \\n(" FILL_REG " .fi\n");
  283.   printf(".br\n");
  284.   printf(".rr " EQN_NO_EXTRA_SPACE_REG "\n");
  285.   // this is a little gross
  286.   set_location(current_filename, current_lineno);
  287.   fputs(flyback_flag ? ".PF\n" : ".PE\n", stdout);
  288. }
  289.  
  290. void troff_output::command(const char *s,
  291.                const char *filename, int lineno)
  292. {
  293.   if (filename != 0)
  294.     set_location(filename, lineno);
  295.   fputs(s, stdout);
  296.   putchar('\n');
  297. }
  298.  
  299. void troff_output::simple_circle(int filled, const position ¢, double rad)
  300. {
  301.   position c = transform(cent);
  302.   printf("\\h'%.3fi'"
  303.      "\\v'%.3fi'"
  304.      "\\D'%c%.3fi'"
  305.      "\n.sp -1\n",
  306.      c.x - rad/scale,
  307.      c.y,
  308.      (filled ? 'C' : 'c'),
  309.      rad*2.0/scale);
  310. }
  311.  
  312. void troff_output::simple_ellipse(int filled, const position ¢,
  313.                   const distance &dim)
  314. {
  315.   position c = transform(cent);
  316.   printf("\\h'%.3fi'"
  317.      "\\v'%.3fi'"
  318.      "\\D'%c%.3fi %.3fi%'"
  319.      "\n.sp -1\n",
  320.      c.x - dim.x/(2.0*scale),
  321.      c.y,
  322.      (filled ? 'E' : 'e'),
  323.      dim.x/scale, dim.y/scale);
  324. }
  325.  
  326. void troff_output::simple_arc(const position &start, const distance ¢,
  327.                   const distance &end)
  328. {
  329.   position s = transform(start);
  330.   position c = transform(cent);
  331.   distance cv = c - s;
  332.   distance ev = transform(end) - c;
  333.   printf("\\h'%.3fi'"
  334.      "\\v'%.3fi'"
  335.      "\\D'a%.3fi %.3fi %.3fi %.3fi'"
  336.      "\n.sp -1\n",
  337.      s.x, s.y, cv.x, cv.y, ev.x, ev.y);
  338. }
  339.  
  340. void troff_output::simple_line(const position &start, const position &end)
  341. {
  342.   position s = transform(start);
  343.   distance ev = transform(end) - s;
  344.   printf("\\h'%.3fi'"
  345.      "\\v'%.3fi'"
  346.      "\\D'l%.3fi %.3fi'"
  347.      "\n.sp -1\n",
  348.      s.x, s.y, ev.x, ev.y);
  349. }
  350.  
  351. void troff_output::simple_spline(const position &start,
  352.                  const position *v, int n)
  353. {
  354.   position pos = transform(start);
  355.   printf("\\h'%.3fi'"
  356.      "\\v'%.3fi'",
  357.      pos.x, pos.y);
  358.   fputs("\\D'~", stdout);
  359.   for (int i = 0; i < n; i++) {
  360.     position temp = transform(v[i]);
  361.     distance v = temp - pos;
  362.     pos = temp;
  363.     if (i != 0)
  364.       putchar(' ');
  365.     printf("%.3fi %.3fi", v.x, v.y);
  366.   }
  367.   printf("'\n.sp -1\n");
  368. }
  369.  
  370. // a solid polygon
  371.  
  372. void troff_output::simple_polygon(int filled, const position *v, int n)
  373. {
  374.   position pos = transform(v[0]);
  375.   printf("\\h'%.3fi'"
  376.      "\\v'%.3fi'",
  377.      pos.x, pos.y);
  378.   printf("\\D'%c", (filled ? 'P' : 'p'));
  379.   for (int i = 1; i < n; i++) {
  380.     position temp = transform(v[i]);
  381.     distance v = temp - pos;
  382.     pos = temp;
  383.     if (i != 1)
  384.       putchar(' ');
  385.     printf("%.3fi %.3fi", v.x, v.y);
  386.   }
  387.   printf("'\n.sp -1\n");
  388. }
  389.  
  390. const double TEXT_AXIS = 0.22;    // in ems
  391.  
  392. static const char *choose_delimiter(const char *text)
  393. {
  394.   if (strchr(text, '\'') == 0)
  395.     return "'";
  396.   else
  397.     return "\\(ts";
  398. }
  399.  
  400. void troff_output::text(const position ¢er, text_piece *v, int n, double)
  401. {
  402.   for (int i = 0; i < n; i++)
  403.     if (v[i].text != 0 && *v[i].text != '\0') {
  404.       position c = transform(center);
  405.       if (v[i].filename != 0)
  406.     set_location(v[i].filename, v[i].lineno);
  407.       printf("\\h'%.3fi", c.x);
  408.       const char *delim = choose_delimiter(v[i].text);
  409.       if (v[i].adj.h == RIGHT_ADJUST)
  410.     printf("-\\w%s%s%su", delim, v[i].text, delim);
  411.       else if (v[i].adj.h != LEFT_ADJUST)
  412.     printf("-(\\w%s%s%su/2u)", delim, v[i].text, delim);
  413.       putchar('\'');
  414.       printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
  415.          c.y,
  416.          n - 1,
  417.          i,
  418.          TEXT_AXIS);
  419.       if (v[i].adj.v == ABOVE_ADJUST)
  420.     printf("-.5v");
  421.       else if (v[i].adj.v == BELOW_ADJUST)
  422.     printf("+.5v");
  423.       putchar('\'');
  424.       fputs(v[i].text, stdout);
  425.       fputs("\n.sp -1\n", stdout);
  426.     }
  427. }
  428.  
  429. void troff_output::line_thickness(double p)
  430. {
  431.   if (p < 0.0)
  432.     p = RELATIVE_THICKNESS;
  433.   if (driver_extension_flag && p != last_line_thickness) {
  434.     printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p, -p);
  435.     last_line_thickness = p;
  436.   }
  437. }
  438.  
  439. void troff_output::set_fill(double f)
  440. {
  441.   if (driver_extension_flag && f != last_fill) {
  442.     printf("\\D'f %du'\\h'%du'\n.sp -1\n", int(f*FILL_MAX), -int(f*FILL_MAX));
  443.     last_fill = f;
  444.   }
  445. }
  446.  
  447. const double DOT_AXIS = .044;
  448.  
  449. void troff_output::dot(const position ¢, const line_type <)
  450. {
  451.   if (zero_length_line_flag) {
  452.     line_thickness(lt.thickness);
  453.     simple_line(cent, cent);
  454.   }
  455.   else {
  456.     position c = transform(cent);
  457.     printf("\\h'%.3fi-(\\w'.'u/2u)'"
  458.        "\\v'%.3fi+%.2fm'"
  459.        ".\n.sp -1\n",
  460.        c.x,
  461.        c.y, 
  462.        DOT_AXIS);
  463.   }
  464. }
  465.  
  466. void troff_output::set_location(const char *s, int n)
  467. {
  468.   if (last_filename != 0 && strcmp(s, last_filename) == 0)
  469.     printf(".lf %d\n", n);
  470.   else {
  471.     printf(".lf %d %s\n", n, s);
  472.     last_filename = s;
  473.   }
  474. }
  475.  
  476. class grops_output : public troff_output {
  477. public:
  478.   grops_output();
  479.   ~grops_output();
  480.   void text(const position &, text_piece *, int, double);
  481. };
  482.  
  483. grops_output::grops_output()
  484. {
  485. }
  486.  
  487. grops_output::~grops_output()
  488. {
  489. }
  490.  
  491. output *make_grops_output()
  492. {
  493.   return new grops_output;
  494. }
  495.  
  496. void grops_output::text(const position ¢er, text_piece *v, int n,
  497.             double ang)
  498. {
  499.   int rotate_flag = 0;
  500.   if (ang != 0.0) {
  501.     rotate_flag = 1;
  502.     position c = transform(center);
  503. #if 0
  504.     printf("\\h'%.3fi'"
  505.        "\\v'%.3fi'"
  506.        "\\X'ps: rotate %.4f'"
  507.        "\n.sp -1\n",
  508.        c.x, c.y, -ang*180.0/M_PI);
  509. #else
  510.     printf("\\h'%.3fi'"
  511.        "\\v'%.3fi'"
  512.        "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
  513.        "\n.sp -1\n",
  514.        c.x, c.y, -ang*180.0/M_PI);
  515. #endif
  516.   }
  517.   troff_output::text(center, v, n, ang);
  518.   if (rotate_flag)
  519. #if 0
  520.     printf("\\X'ps: end rotate'\n.sp -1\n");
  521. #else
  522.     printf("\\X'ps: exec grestore'\n.sp -1\n");
  523. #endif
  524. }
  525.