xref: /trueos/contrib/groff/src/preproc/pic/tex.cpp (revision 513cdf04e173130783343fe42786eef6b8294c6e)
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2003 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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, 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 
milliinches(double x)68 inline int milliinches(double x)
69 {
70   return int(x*1000.0 + .5);
71 }
72 
transform(const position & pos)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 
make_tex_output()79 output *make_tex_output()
80 {
81   return new tex_output;
82 }
83 
tex_output()84 tex_output::tex_output()
85 {
86 }
87 
~tex_output()88 tex_output::~tex_output()
89 {
90 }
91 
92 const int DEFAULT_PEN_SIZE = 8;
93 
set_pen_size(double ps)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 
start_picture(double sc,const position & ll,const position & ur)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   /* \newbox and \newdimen are defined with \outer in plain.tex and can't
118      be used directly in an \if clause. */
119   printf("\\expandafter\\ifx\\csname %s\\endcsname\\relax\n"
120 	 "   \\csname newbox\\expandafter\\endcsname\\csname %s\\endcsname\n"
121 	 "\\fi\n"
122 	 "\\ifx\\graphtemp\\undefined\n"
123 	 "  \\csname newdimen\\endcsname\\graphtemp\n"
124 	 "\\fi\n"
125 	 "\\expandafter\\setbox\\csname %s\\endcsname\n"
126 	 " =\\vtop{\\vskip 0pt\\hbox{%%\n",
127 	 graphname, graphname, graphname);
128   pen_size = -2.0;
129 }
130 
finish_picture()131 void tex_output::finish_picture()
132 {
133   printf("    \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n"
134 	 "    \\kern %.3fin\n"
135 	 "  }%%\n"
136 	 "}%%\n",
137 	 height, width);
138 }
139 
text(const position & center,text_piece * v,int n,double)140 void tex_output::text(const position &center, text_piece *v, int n, double)
141 {
142   position c = transform(center);
143   for (int i = 0; i < n; i++)
144     if (v[i].text != 0 && *v[i].text != '\0') {
145       int j = 2*i - n + 1;
146       if (v[i].adj.v == ABOVE_ADJUST)
147 	j--;
148       else if (v[i].adj.v == BELOW_ADJUST)
149 	j++;
150       if (j == 0) {
151 	printf("    \\graphtemp=.5ex\n"
152 	       "    \\advance\\graphtemp by %.3fin\n", c.y);
153       }
154       else {
155 	printf("    \\graphtemp=\\baselineskip\n"
156 	       "    \\multiply\\graphtemp by %d\n"
157 	       "    \\divide\\graphtemp by 2\n"
158 	       "    \\advance\\graphtemp by .5ex\n"
159 	       "    \\advance\\graphtemp by %.3fin\n",
160 	       j, c.y);
161       }
162       printf("    \\rlap{\\kern %.3fin\\lower\\graphtemp", c.x);
163       fputs("\\hbox to 0pt{", stdout);
164       if (v[i].adj.h != LEFT_ADJUST)
165 	fputs("\\hss ", stdout);
166       fputs(v[i].text, stdout);
167       if (v[i].adj.h != RIGHT_ADJUST)
168 	fputs("\\hss", stdout);
169       fputs("}}%\n", stdout);
170     }
171 }
172 
point(const position & pos)173 void tex_output::point(const position &pos)
174 {
175   position p = transform(pos);
176   printf("    \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y));
177 }
178 
line(const position & start,const position * v,int n,const line_type & lt)179 void tex_output::line(const position &start, const position *v, int n,
180 		      const line_type &lt)
181 {
182   set_pen_size(lt.thickness);
183   point(start);
184   for (int i = 0; i < n; i++)
185     point(v[i]);
186   fputs("    \\special{", stdout);
187   switch(lt.type) {
188   case line_type::invisible:
189     fputs("ip", stdout);
190     break;
191   case line_type::solid:
192     fputs("fp", stdout);
193     break;
194   case line_type::dotted:
195     printf("dt %.3f", lt.dash_width/scale);
196     break;
197   case line_type::dashed:
198     printf("da %.3f", lt.dash_width/scale);
199     break;
200   }
201   fputs("}%\n", stdout);
202 }
203 
polygon(const position * v,int n,const line_type & lt,double fill)204 void tex_output::polygon(const position *v, int n,
205 			 const line_type &lt, double fill)
206 {
207   if (fill >= 0.0) {
208     if (fill > 1.0)
209       fill = 1.0;
210     printf("    \\special{sh %.3f}%%\n", fill);
211   }
212   line(v[n-1], v, n, lt);
213 }
214 
spline(const position & start,const position * v,int n,const line_type & lt)215 void tex_output::spline(const position &start, const position *v, int n,
216 			const line_type &lt)
217 {
218   if (lt.type == line_type::invisible)
219     return;
220   set_pen_size(lt.thickness);
221   point(start);
222   for (int i = 0; i < n; i++)
223     point(v[i]);
224   fputs("    \\special{sp", stdout);
225   switch(lt.type) {
226   case line_type::solid:
227     break;
228   case line_type::dotted:
229     printf(" %.3f", -lt.dash_width/scale);
230     break;
231   case line_type::dashed:
232     printf(" %.3f", lt.dash_width/scale);
233     break;
234   case line_type::invisible:
235     assert(0);
236   }
237   fputs("}%\n", stdout);
238 }
239 
solid_arc(const position & cent,double rad,double start_angle,double end_angle,const line_type & lt)240 void tex_output::solid_arc(const position &cent, double rad,
241 			   double start_angle, double end_angle,
242 			   const line_type &lt)
243 {
244   set_pen_size(lt.thickness);
245   position c = transform(cent);
246   printf("    \\special{ar %d %d %d %d %f %f}%%\n",
247 	 milliinches(c.x),
248 	 milliinches(c.y),
249 	 milliinches(rad/scale),
250 	 milliinches(rad/scale),
251 	 -end_angle,
252 	 (-end_angle > -start_angle) ? (double)M_PI * 2 - start_angle
253 	 			     : -start_angle);
254 }
255 
arc(const position & start,const position & cent,const position & end,const line_type & lt)256 void tex_output::arc(const position &start, const position &cent,
257 		     const position &end, const line_type &lt)
258 {
259   switch (lt.type) {
260   case line_type::invisible:
261     break;
262   case line_type::dashed:
263     dashed_arc(start, cent, end, lt);
264     break;
265   case line_type::dotted:
266     dotted_arc(start, cent, end, lt);
267     break;
268   case line_type::solid:
269     {
270       position c;
271       if (!compute_arc_center(start, cent, end, &c)) {
272 	line(start, &end, 1, lt);
273 	break;
274       }
275       solid_arc(c,
276 		hypot(cent - start),
277 		atan2(start.y - c.y, start.x - c.x),
278 		atan2(end.y - c.y, end.x - c.x),
279 		lt);
280       break;
281     }
282   }
283 }
284 
circle(const position & cent,double rad,const line_type & lt,double fill)285 void tex_output::circle(const position &cent, double rad,
286 			const line_type &lt, double fill)
287 {
288   if (fill >= 0.0 && lt.type != line_type::solid) {
289     if (fill > 1.0)
290       fill = 1.0;
291     line_type ilt;
292     ilt.type = line_type::invisible;
293     ellipse(cent, position(rad*2.0, rad*2.0), ilt, fill);
294   }
295   switch (lt.type) {
296   case line_type::dashed:
297     dashed_circle(cent, rad, lt);
298     break;
299   case line_type::invisible:
300     break;
301   case line_type::solid:
302     ellipse(cent, position(rad*2.0,rad*2.0), lt, fill);
303     break;
304   case line_type::dotted:
305     dotted_circle(cent, rad, lt);
306     break;
307   default:
308     assert(0);
309   }
310 }
311 
ellipse(const position & cent,const distance & dim,const line_type & lt,double fill)312 void tex_output::ellipse(const position &cent, const distance &dim,
313 			 const line_type &lt, double fill)
314 {
315   if (lt.type == line_type::invisible) {
316     if (fill < 0.0)
317       return;
318   }
319   else
320     set_pen_size(lt.thickness);
321   if (fill >= 0.0) {
322     if (fill > 1.0)
323       fill = 1.0;
324     printf("    \\special{sh %.3f}%%\n", fill);
325   }
326   position c = transform(cent);
327   switch (lt.type) {
328   case line_type::solid:
329   case line_type::invisible:
330     printf("    \\special{%s %d %d %d %d 0 6.28319}%%\n",
331 	   (lt.type == line_type::invisible ? "ia" : "ar"),
332 	   milliinches(c.x),
333 	   milliinches(c.y),
334 	   milliinches(dim.x/(2.0*scale)),
335 	   milliinches(dim.y/(2.0*scale)));
336     break;
337   case line_type::dashed:
338     dashed_ellipse(cent, dim / scale, lt);
339     break;
340   case line_type::dotted:
341     dotted_ellipse(cent, dim / scale, lt);
342     break;
343   default:
344     assert(0);
345   }
346 }
347 
command(const char * s,const char *,int)348 void tex_output::command(const char *s, const char *, int)
349 {
350   fputs(s, stdout);
351   putchar('%');			// avoid unwanted spaces
352   putchar('\n');
353 }
354 
supports_filled_polygons()355 int tex_output::supports_filled_polygons()
356 {
357   return 1;
358 }
359 
dot(const position & pos,const line_type & lt)360 void tex_output::dot(const position &pos, const line_type &lt)
361 {
362   if (zero_length_line_flag) {
363     line_type slt = lt;
364     slt.type = line_type::solid;
365     line(pos, &pos, 1, slt);
366   }
367   else {
368     int dot_rad = int(lt.thickness*(1000.0/(72.0*2)) + .5);
369     if (dot_rad == 0)
370       dot_rad = 1;
371     position p = transform(pos);
372     printf("    \\special{sh 1}%%\n"
373 	   "    \\special{ia %d %d %d %d 0 6.28319}%%\n",
374 	   milliinches(p.x), milliinches(p.y), dot_rad, dot_rad);
375   }
376 }
377 
set_color(char *,char *)378 void tex_output::set_color(char *, char *)
379 {
380   /* not implemented yet */
381 }
382 
reset_color()383 void tex_output::reset_color()
384 {
385   /* not implemented yet */
386 }
387 
get_last_filled()388 char *tex_output::get_last_filled()
389 {
390   /* not implemented yet */
391   return NULL;
392 }
393 
get_outline_color()394 char *tex_output::get_outline_color()
395 {
396   /* not implemented yet */
397   return NULL;
398 }
399 
400 class tpic_output : public tex_output {
401 public:
402   tpic_output();
403   void command(const char *, const char *, int);
404 private:
405   void set_pen_size(double ps);
406   int default_pen_size;
407   int prev_default_pen_size;
408 };
409 
tpic_output()410 tpic_output::tpic_output()
411 : default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE)
412 {
413 }
414 
command(const char * s,const char * filename,int lineno)415 void tpic_output::command(const char *s, const char *filename, int lineno)
416 {
417   assert(s[0] == '.');
418   if (s[1] == 'p' && s[2] == 's' && (s[3] == '\0' || !csalpha(s[3]))) {
419     const char *p = s + 3;
420     while (csspace(*p))
421       p++;
422     if (*p == '\0') {
423       int temp = default_pen_size;
424       default_pen_size = prev_default_pen_size;
425       prev_default_pen_size = temp;
426     }
427     else {
428       char *ptr;
429       int temp = (int)strtol(p, &ptr, 10);
430       if (temp == 0 && ptr == p)
431 	error_with_file_and_line(filename, lineno,
432 				 "argument to `.ps' not an integer");
433       else if (temp < 0)
434 	error_with_file_and_line(filename, lineno,
435 				 "negative pen size");
436       else {
437 	prev_default_pen_size = default_pen_size;
438 	default_pen_size = temp;
439       }
440     }
441   }
442   else
443     printf("\\%s%%\n", s + 1);
444 }
445 
set_pen_size(double ps)446 void tpic_output::set_pen_size(double ps)
447 {
448   if (ps < 0.0)
449     printf("    \\special{pn %d}%%\n", default_pen_size);
450   else
451     tex_output::set_pen_size(ps);
452 }
453 
make_tpic_output()454 output *make_tpic_output()
455 {
456   return new tpic_output;
457 }
458 
459 #endif
460