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