* All affected files: Update postal address of FSF.
[s-roff.git] / src / preproc / pic / tex.cpp
blobf997b868d6876c0c9a3ed02afd8860130fc7bce9
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
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.
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.
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. */
21 #include "pic.h"
23 #ifdef TEX_SUPPORT
25 #include "common.h"
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;
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);
66 // convert inches to milliinches
68 inline int milliinches(double x)
70 return int(x*1000.0 + .5);
73 inline position tex_output::transform(const position &pos)
75 return position((pos.x - upper_left.x)/scale,
76 (upper_left.y - pos.y)/scale);
79 output *make_tex_output()
81 return new tex_output;
84 tex_output::tex_output()
88 tex_output::~tex_output()
92 const int DEFAULT_PEN_SIZE = 8;
94 void tex_output::set_pen_size(double ps)
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));
105 void tex_output::start_picture(double sc, const position &ll,
106 const position &ur)
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;
131 void tex_output::finish_picture()
133 printf(" \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n"
134 " \\kern %.3fin\n"
135 " }%%\n"
136 "}%%\n",
137 height, width);
140 void tex_output::text(const position &center, text_piece *v, int n, double)
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);
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);
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);
173 void tex_output::point(const position &pos)
175 position p = transform(pos);
176 printf(" \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y));
179 void tex_output::line(const position &start, const position *v, int n,
180 const line_type &lt)
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;
201 fputs("}%\n", stdout);
204 void tex_output::polygon(const position *v, int n,
205 const line_type &lt, double fill)
207 if (fill >= 0.0) {
208 if (fill > 1.0)
209 fill = 1.0;
210 printf(" \\special{sh %.3f}%%\n", fill);
212 line(v[n-1], v, n, lt);
215 void tex_output::spline(const position &start, const position *v, int n,
216 const line_type &lt)
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);
237 fputs("}%\n", stdout);
240 void tex_output::solid_arc(const position &cent, double rad,
241 double start_angle, double end_angle,
242 const line_type &lt)
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);
256 void tex_output::arc(const position &start, const position &cent,
257 const position &end, const line_type &lt)
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:
270 position c;
271 if (!compute_arc_center(start, cent, end, &c)) {
272 line(start, &end, 1, lt);
273 break;
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;
285 void tex_output::circle(const position &cent, double rad,
286 const line_type &lt, double fill)
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);
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);
312 void tex_output::ellipse(const position &cent, const distance &dim,
313 const line_type &lt, double fill)
315 if (lt.type == line_type::invisible) {
316 if (fill < 0.0)
317 return;
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);
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);
348 void tex_output::command(const char *s, const char *, int)
350 fputs(s, stdout);
351 putchar('%'); // avoid unwanted spaces
352 putchar('\n');
355 int tex_output::supports_filled_polygons()
357 return 1;
360 void tex_output::dot(const position &pos, const line_type &lt)
362 if (zero_length_line_flag) {
363 line_type slt = lt;
364 slt.type = line_type::solid;
365 line(pos, &pos, 1, slt);
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);
378 void tex_output::set_color(char *, char *)
380 /* not implemented yet */
383 void tex_output::reset_color()
385 /* not implemented yet */
388 char *tex_output::get_last_filled()
390 /* not implemented yet */
391 return NULL;
394 char *tex_output::get_outline_color()
396 /* not implemented yet */
397 return NULL;
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;
410 tpic_output::tpic_output()
411 : default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE)
415 void tpic_output::command(const char *s, const char *filename, int lineno)
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;
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;
442 else
443 printf("\\%s%%\n", s + 1);
446 void tpic_output::set_pen_size(double ps)
448 if (ps < 0.0)
449 printf(" \\special{pn %d}%%\n", default_pen_size);
450 else
451 tex_output::set_pen_size(ps);
454 output *make_tpic_output()
456 return new tpic_output;
459 #endif