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