No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / groff / src / preproc / pic / tex.cpp
blob191b757bb4b5f0ebf7c2635859c4b9497843ca67
1 /* $NetBSD$ */
3 // -*- C++ -*-
4 /* Copyright (C) 1989, 1990, 1991, 1992, 2003 Free Software Foundation, Inc.
5 Written by James Clark (jjc@jclark.com)
7 This file is part of groff.
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.
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.
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. */
23 #include "pic.h"
25 #ifdef TEX_SUPPORT
27 #include "common.h"
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;
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);
68 // convert inches to milliinches
70 inline int milliinches(double x)
72 return int(x*1000.0 + .5);
75 inline position tex_output::transform(const position &pos)
77 return position((pos.x - upper_left.x)/scale,
78 (upper_left.y - pos.y)/scale);
81 output *make_tex_output()
83 return new tex_output;
86 tex_output::tex_output()
90 tex_output::~tex_output()
94 const int DEFAULT_PEN_SIZE = 8;
96 void tex_output::set_pen_size(double ps)
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));
107 void tex_output::start_picture(double sc, const position &ll,
108 const position &ur)
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;
133 void tex_output::finish_picture()
135 printf(" \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n"
136 " \\kern %.3fin\n"
137 " }%%\n"
138 "}%%\n",
139 height, width);
142 void tex_output::text(const position &center, text_piece *v, int n, double)
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);
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);
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);
175 void tex_output::point(const position &pos)
177 position p = transform(pos);
178 printf(" \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y));
181 void tex_output::line(const position &start, const position *v, int n,
182 const line_type &lt)
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;
203 fputs("}%\n", stdout);
206 void tex_output::polygon(const position *v, int n,
207 const line_type &lt, double fill)
209 if (fill >= 0.0) {
210 if (fill > 1.0)
211 fill = 1.0;
212 printf(" \\special{sh %.3f}%%\n", fill);
214 line(v[n-1], v, n, lt);
217 void tex_output::spline(const position &start, const position *v, int n,
218 const line_type &lt)
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);
239 fputs("}%\n", stdout);
242 void tex_output::solid_arc(const position &cent, double rad,
243 double start_angle, double end_angle,
244 const line_type &lt)
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);
258 void tex_output::arc(const position &start, const position &cent,
259 const position &end, const line_type &lt)
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:
272 position c;
273 if (!compute_arc_center(start, cent, end, &c)) {
274 line(start, &end, 1, lt);
275 break;
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;
287 void tex_output::circle(const position &cent, double rad,
288 const line_type &lt, double fill)
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);
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);
314 void tex_output::ellipse(const position &cent, const distance &dim,
315 const line_type &lt, double fill)
317 if (lt.type == line_type::invisible) {
318 if (fill < 0.0)
319 return;
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);
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);
350 void tex_output::command(const char *s, const char *, int)
352 fputs(s, stdout);
353 putchar('%'); // avoid unwanted spaces
354 putchar('\n');
357 int tex_output::supports_filled_polygons()
359 return 1;
362 void tex_output::dot(const position &pos, const line_type &lt)
364 if (zero_length_line_flag) {
365 line_type slt = lt;
366 slt.type = line_type::solid;
367 line(pos, &pos, 1, slt);
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);
380 void tex_output::set_color(char *, char *)
382 /* not implemented yet */
385 void tex_output::reset_color()
387 /* not implemented yet */
390 char *tex_output::get_last_filled()
392 /* not implemented yet */
393 return NULL;
396 char *tex_output::get_outline_color()
398 /* not implemented yet */
399 return NULL;
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;
412 tpic_output::tpic_output()
413 : default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE)
417 void tpic_output::command(const char *s, const char *filename, int lineno)
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;
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;
444 else
445 printf("\\%s%%\n", s + 1);
448 void tpic_output::set_pen_size(double ps)
450 if (ps < 0.0)
451 printf(" \\special{pn %d}%%\n", default_pen_size);
452 else
453 tex_output::set_pen_size(ps);
456 output *make_tpic_output()
458 return new tpic_output;
461 #endif