xref: /netbsd-src/external/gpl2/groff/dist/src/preproc/pic/tex.cpp (revision 89a07cf815a29524268025a1139fac4c5190f765)
1 /*	$NetBSD: tex.cpp,v 1.1.1.1 2016/01/13 18:41:48 christos Exp $	*/
2 
3 // -*- C++ -*-
4 /* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc.
5      Written by James Clark (jjc@jclark.com)
6 
7 This file is part of groff.
8 
9 groff is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2, or (at your option) any later
12 version.
13 
14 groff is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18 
19 You should have received a copy of the GNU General Public License along
20 with groff; see the file COPYING.  If not, write to the Free Software
21 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
22 
23 #include "pic.h"
24 
25 #ifdef TEX_SUPPORT
26 
27 #include "common.h"
28 
29 class tex_output : public common_output {
30 public:
31   tex_output();
32   ~tex_output();
33   void start_picture(double, const position &ll, const position &ur);
34   void finish_picture();
35   void text(const position &, text_piece *, int, double);
36   void line(const position &, const position *, int n,
37 	    const line_type &);
38   void polygon(const position *, int n,
39 	       const line_type &, double);
40   void spline(const position &, const position *, int n,
41 	      const line_type &);
42   void arc(const position &, const position &, const position &,
43 	   const line_type &);
44   void circle(const position &, double rad, const line_type &, double);
45   void ellipse(const position &, const distance &, const line_type &, double);
46   void command(const char *, const char *, int);
47   void set_color(char *, char *);
48   void reset_color();
49   char *get_last_filled();
50   char *get_outline_color();
51   int supports_filled_polygons();
52 private:
53   position upper_left;
54   double height;
55   double width;
56   double scale;
57   double pen_size;
58 
59   void point(const position &);
60   void dot(const position &, const line_type &);
61   void solid_arc(const position &cent, double rad, double start_angle,
62 		 double end_angle, const line_type &lt);
63   position transform(const position &);
64 protected:
65   virtual void set_pen_size(double ps);
66 };
67 
68 // convert inches to milliinches
69 
milliinches(double x)70 inline int milliinches(double x)
71 {
72   return int(x*1000.0 + .5);
73 }
74 
transform(const position & pos)75 inline position tex_output::transform(const position &pos)
76 {
77   return position((pos.x - upper_left.x)/scale,
78 		  (upper_left.y - pos.y)/scale);
79 }
80 
make_tex_output()81 output *make_tex_output()
82 {
83   return new tex_output;
84 }
85 
tex_output()86 tex_output::tex_output()
87 {
88 }
89 
~tex_output()90 tex_output::~tex_output()
91 {
92 }
93 
94 const int DEFAULT_PEN_SIZE = 8;
95 
set_pen_size(double ps)96 void tex_output::set_pen_size(double ps)
97 {
98   if (ps < 0.0)
99     ps = -1.0;
100   if (ps != pen_size) {
101     pen_size = ps;
102     printf("    \\special{pn %d}%%\n",
103 	   ps < 0.0 ? DEFAULT_PEN_SIZE : int(ps*(1000.0/72.0) + .5));
104   }
105 }
106 
start_picture(double sc,const position & ll,const position & ur)107 void tex_output::start_picture(double sc, const position &ll,
108 			       const position &ur)
109 {
110   upper_left.x = ll.x;
111   upper_left.y = ur.y;
112   scale = compute_scale(sc, ll, ur);
113   height = (ur.y - ll.y)/scale;
114   width = (ur.x - ll.x)/scale;
115   /* The point of \vskip 0pt is to ensure that the vtop gets
116      a height of 0 rather than the height of the hbox; this
117      might be non-zero if text from text attributes lies outside pic's
118      idea of the bounding box of the picture. */
119   /* \newbox and \newdimen are defined with \outer in plain.tex and can't
120      be used directly in an \if clause. */
121   printf("\\expandafter\\ifx\\csname %s\\endcsname\\relax\n"
122 	 "   \\csname newbox\\expandafter\\endcsname\\csname %s\\endcsname\n"
123 	 "\\fi\n"
124 	 "\\ifx\\graphtemp\\undefined\n"
125 	 "  \\csname newdimen\\endcsname\\graphtemp\n"
126 	 "\\fi\n"
127 	 "\\expandafter\\setbox\\csname %s\\endcsname\n"
128 	 " =\\vtop{\\vskip 0pt\\hbox{%%\n",
129 	 graphname, graphname, graphname);
130   pen_size = -2.0;
131 }
132 
finish_picture()133 void tex_output::finish_picture()
134 {
135   printf("    \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n"
136 	 "    \\kern %.3fin\n"
137 	 "  }%%\n"
138 	 "}%%\n",
139 	 height, width);
140 }
141 
text(const position & center,text_piece * v,int n,double)142 void tex_output::text(const position &center, text_piece *v, int n, double)
143 {
144   position c = transform(center);
145   for (int i = 0; i < n; i++)
146     if (v[i].text != 0 && *v[i].text != '\0') {
147       int j = 2*i - n + 1;
148       if (v[i].adj.v == ABOVE_ADJUST)
149 	j--;
150       else if (v[i].adj.v == BELOW_ADJUST)
151 	j++;
152       if (j == 0) {
153 	printf("    \\graphtemp=.5ex\n"
154 	       "    \\advance\\graphtemp by %.3fin\n", c.y);
155       }
156       else {
157 	printf("    \\graphtemp=\\baselineskip\n"
158 	       "    \\multiply\\graphtemp by %d\n"
159 	       "    \\divide\\graphtemp by 2\n"
160 	       "    \\advance\\graphtemp by .5ex\n"
161 	       "    \\advance\\graphtemp by %.3fin\n",
162 	       j, c.y);
163       }
164       printf("    \\rlap{\\kern %.3fin\\lower\\graphtemp", c.x);
165       fputs("\\hbox to 0pt{", stdout);
166       if (v[i].adj.h != LEFT_ADJUST)
167 	fputs("\\hss ", stdout);
168       fputs(v[i].text, stdout);
169       if (v[i].adj.h != RIGHT_ADJUST)
170 	fputs("\\hss", stdout);
171       fputs("}}%\n", stdout);
172     }
173 }
174 
point(const position & pos)175 void tex_output::point(const position &pos)
176 {
177   position p = transform(pos);
178   printf("    \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y));
179 }
180 
line(const position & start,const position * v,int n,const line_type & lt)181 void tex_output::line(const position &start, const position *v, int n,
182 		      const line_type &lt)
183 {
184   set_pen_size(lt.thickness);
185   point(start);
186   for (int i = 0; i < n; i++)
187     point(v[i]);
188   fputs("    \\special{", stdout);
189   switch(lt.type) {
190   case line_type::invisible:
191     fputs("ip", stdout);
192     break;
193   case line_type::solid:
194     fputs("fp", stdout);
195     break;
196   case line_type::dotted:
197     printf("dt %.3f", lt.dash_width/scale);
198     break;
199   case line_type::dashed:
200     printf("da %.3f", lt.dash_width/scale);
201     break;
202   }
203   fputs("}%\n", stdout);
204 }
205 
polygon(const position * v,int n,const line_type & lt,double fill)206 void tex_output::polygon(const position *v, int n,
207 			 const line_type &lt, double fill)
208 {
209   if (fill >= 0.0) {
210     if (fill > 1.0)
211       fill = 1.0;
212     printf("    \\special{sh %.3f}%%\n", fill);
213   }
214   line(v[n-1], v, n, lt);
215 }
216 
spline(const position & start,const position * v,int n,const line_type & lt)217 void tex_output::spline(const position &start, const position *v, int n,
218 			const line_type &lt)
219 {
220   if (lt.type == line_type::invisible)
221     return;
222   set_pen_size(lt.thickness);
223   point(start);
224   for (int i = 0; i < n; i++)
225     point(v[i]);
226   fputs("    \\special{sp", stdout);
227   switch(lt.type) {
228   case line_type::solid:
229     break;
230   case line_type::dotted:
231     printf(" %.3f", -lt.dash_width/scale);
232     break;
233   case line_type::dashed:
234     printf(" %.3f", lt.dash_width/scale);
235     break;
236   case line_type::invisible:
237     assert(0);
238   }
239   fputs("}%\n", stdout);
240 }
241 
solid_arc(const position & cent,double rad,double start_angle,double end_angle,const line_type & lt)242 void tex_output::solid_arc(const position &cent, double rad,
243 			   double start_angle, double end_angle,
244 			   const line_type &lt)
245 {
246   set_pen_size(lt.thickness);
247   position c = transform(cent);
248   printf("    \\special{ar %d %d %d %d %f %f}%%\n",
249 	 milliinches(c.x),
250 	 milliinches(c.y),
251 	 milliinches(rad/scale),
252 	 milliinches(rad/scale),
253 	 -end_angle,
254 	 (-end_angle > -start_angle) ? (double)M_PI * 2 - start_angle
255 	 			     : -start_angle);
256 }
257 
arc(const position & start,const position & cent,const position & end,const line_type & lt)258 void tex_output::arc(const position &start, const position &cent,
259 		     const position &end, const line_type &lt)
260 {
261   switch (lt.type) {
262   case line_type::invisible:
263     break;
264   case line_type::dashed:
265     dashed_arc(start, cent, end, lt);
266     break;
267   case line_type::dotted:
268     dotted_arc(start, cent, end, lt);
269     break;
270   case line_type::solid:
271     {
272       position c;
273       if (!compute_arc_center(start, cent, end, &c)) {
274 	line(start, &end, 1, lt);
275 	break;
276       }
277       solid_arc(c,
278 		hypot(cent - start),
279 		atan2(start.y - c.y, start.x - c.x),
280 		atan2(end.y - c.y, end.x - c.x),
281 		lt);
282       break;
283     }
284   }
285 }
286 
circle(const position & cent,double rad,const line_type & lt,double fill)287 void tex_output::circle(const position &cent, double rad,
288 			const line_type &lt, double fill)
289 {
290   if (fill >= 0.0 && lt.type != line_type::solid) {
291     if (fill > 1.0)
292       fill = 1.0;
293     line_type ilt;
294     ilt.type = line_type::invisible;
295     ellipse(cent, position(rad*2.0, rad*2.0), ilt, fill);
296   }
297   switch (lt.type) {
298   case line_type::dashed:
299     dashed_circle(cent, rad, lt);
300     break;
301   case line_type::invisible:
302     break;
303   case line_type::solid:
304     ellipse(cent, position(rad*2.0,rad*2.0), lt, fill);
305     break;
306   case line_type::dotted:
307     dotted_circle(cent, rad, lt);
308     break;
309   default:
310     assert(0);
311   }
312 }
313 
ellipse(const position & cent,const distance & dim,const line_type & lt,double fill)314 void tex_output::ellipse(const position &cent, const distance &dim,
315 			 const line_type &lt, double fill)
316 {
317   if (lt.type == line_type::invisible) {
318     if (fill < 0.0)
319       return;
320   }
321   else
322     set_pen_size(lt.thickness);
323   if (fill >= 0.0) {
324     if (fill > 1.0)
325       fill = 1.0;
326     printf("    \\special{sh %.3f}%%\n", fill);
327   }
328   position c = transform(cent);
329   switch (lt.type) {
330   case line_type::solid:
331   case line_type::invisible:
332     printf("    \\special{%s %d %d %d %d 0 6.28319}%%\n",
333 	   (lt.type == line_type::invisible ? "ia" : "ar"),
334 	   milliinches(c.x),
335 	   milliinches(c.y),
336 	   milliinches(dim.x/(2.0*scale)),
337 	   milliinches(dim.y/(2.0*scale)));
338     break;
339   case line_type::dashed:
340     dashed_ellipse(cent, dim / scale, lt);
341     break;
342   case line_type::dotted:
343     dotted_ellipse(cent, dim / scale, lt);
344     break;
345   default:
346     assert(0);
347   }
348 }
349 
command(const char * s,const char *,int)350 void tex_output::command(const char *s, const char *, int)
351 {
352   fputs(s, stdout);
353   putchar('%');			// avoid unwanted spaces
354   putchar('\n');
355 }
356 
supports_filled_polygons()357 int tex_output::supports_filled_polygons()
358 {
359   return 1;
360 }
361 
dot(const position & pos,const line_type & lt)362 void tex_output::dot(const position &pos, const line_type &lt)
363 {
364   if (zero_length_line_flag) {
365     line_type slt = lt;
366     slt.type = line_type::solid;
367     line(pos, &pos, 1, slt);
368   }
369   else {
370     int dot_rad = int(lt.thickness*(1000.0/(72.0*2)) + .5);
371     if (dot_rad == 0)
372       dot_rad = 1;
373     position p = transform(pos);
374     printf("    \\special{sh 1}%%\n"
375 	   "    \\special{ia %d %d %d %d 0 6.28319}%%\n",
376 	   milliinches(p.x), milliinches(p.y), dot_rad, dot_rad);
377   }
378 }
379 
set_color(char *,char *)380 void tex_output::set_color(char *, char *)
381 {
382   /* not implemented yet */
383 }
384 
reset_color()385 void tex_output::reset_color()
386 {
387   /* not implemented yet */
388 }
389 
get_last_filled()390 char *tex_output::get_last_filled()
391 {
392   /* not implemented yet */
393   return NULL;
394 }
395 
get_outline_color()396 char *tex_output::get_outline_color()
397 {
398   /* not implemented yet */
399   return NULL;
400 }
401 
402 class tpic_output : public tex_output {
403 public:
404   tpic_output();
405   void command(const char *, const char *, int);
406 private:
407   void set_pen_size(double ps);
408   int default_pen_size;
409   int prev_default_pen_size;
410 };
411 
tpic_output()412 tpic_output::tpic_output()
413 : default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE)
414 {
415 }
416 
command(const char * s,const char * filename,int lineno)417 void tpic_output::command(const char *s, const char *filename, int lineno)
418 {
419   assert(s[0] == '.');
420   if (s[1] == 'p' && s[2] == 's' && (s[3] == '\0' || !csalpha(s[3]))) {
421     const char *p = s + 3;
422     while (csspace(*p))
423       p++;
424     if (*p == '\0') {
425       int temp = default_pen_size;
426       default_pen_size = prev_default_pen_size;
427       prev_default_pen_size = temp;
428     }
429     else {
430       char *ptr;
431       int temp = (int)strtol(p, &ptr, 10);
432       if (temp == 0 && ptr == p)
433 	error_with_file_and_line(filename, lineno,
434 				 "argument to `.ps' not an integer");
435       else if (temp < 0)
436 	error_with_file_and_line(filename, lineno,
437 				 "negative pen size");
438       else {
439 	prev_default_pen_size = default_pen_size;
440 	default_pen_size = temp;
441       }
442     }
443   }
444   else
445     printf("\\%s%%\n", s + 1);
446 }
447 
set_pen_size(double ps)448 void tpic_output::set_pen_size(double ps)
449 {
450   if (ps < 0.0)
451     printf("    \\special{pn %d}%%\n", default_pen_size);
452   else
453     tex_output::set_pen_size(ps);
454 }
455 
make_tpic_output()456 output *make_tpic_output()
457 {
458   return new tpic_output;
459 }
460 
461 #endif
462