Copyright 2017
[s-roff.git] / src / pre-pic / tex.cpp
blob29441e4855b847185fbb328b6c6e123e8d2b39e5
1 /*@
2 * Copyright (c) 2014 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
4 * Copyright (C) 1989 - 1992, 2003 Free Software Foundation, Inc.
5 * Written by James Clark (jjc@jclark.com)
7 * This 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 * This 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.
22 #include "config.h"
23 #include "pic-config.h"
24 #ifdef TEX_SUPPORT
26 #include "common.h"
27 #include "pic.h"
29 class tex_output
30 : public common_output
32 position upper_left;
33 double height;
34 double width;
35 double scale;
36 double pen_size;
38 void point(const position &);
39 void dot(const position &, const line_type &);
40 void solid_arc(const position &cent, double rad, double start_angle,
41 double end_angle, const line_type &lt);
42 position transform(const position &);
44 protected:
45 virtual void set_pen_size(double ps);
47 public:
48 tex_output();
49 ~tex_output();
50 void start_picture(double, const position &ll, const position &ur);
51 void finish_picture();
52 void text(const position &, text_piece *, int, double);
53 void line(const position &, const position *, int n,
54 const line_type &);
55 void polygon(const position *, int n,
56 const line_type &, double);
57 void spline(const position &, const position *, int n,
58 const line_type &);
59 void arc(const position &, const position &, const position &,
60 const line_type &);
61 void circle(const position &, double rad, const line_type &, double);
62 void ellipse(const position &, const distance &, const line_type &, double);
63 void command(const char *, const char *, int);
64 void set_color(char *, char *);
65 void reset_color();
66 char *get_last_filled();
67 char *get_outline_color();
68 int supports_filled_polygons();
71 // convert inches to milliinches
73 inline int milliinches(double x)
75 return int(x*1000.0 + .5);
78 inline position tex_output::transform(const position &pos)
80 return position((pos.x - upper_left.x)/scale,
81 (upper_left.y - pos.y)/scale);
84 output *make_tex_output()
86 return new tex_output;
89 tex_output::tex_output()
93 tex_output::~tex_output()
97 const int DEFAULT_PEN_SIZE = 8;
99 void tex_output::set_pen_size(double ps)
101 if (ps < 0.0)
102 ps = -1.0;
103 if (ps != pen_size) {
104 pen_size = ps;
105 printf(" \\special{pn %d}%%\n",
106 ps < 0.0 ? DEFAULT_PEN_SIZE : int(ps*(1000.0/72.0) + .5));
110 void tex_output::start_picture(double sc, const position &ll,
111 const position &ur)
113 upper_left.x = ll.x;
114 upper_left.y = ur.y;
115 scale = compute_scale(sc, ll, ur);
116 height = (ur.y - ll.y)/scale;
117 width = (ur.x - ll.x)/scale;
118 /* The point of \vskip 0pt is to ensure that the vtop gets
119 a height of 0 rather than the height of the hbox; this
120 might be non-zero if text from text attributes lies outside pic's
121 idea of the bounding box of the picture. */
122 /* \newbox and \newdimen are defined with \outer in plain.tex and can't
123 be used directly in an \if clause. */
124 printf("\\expandafter\\ifx\\csname %s\\endcsname\\relax\n"
125 " \\csname newbox\\expandafter\\endcsname\\csname %s\\endcsname\n"
126 "\\fi\n"
127 "\\ifx\\graphtemp\\undefined\n"
128 " \\csname newdimen\\endcsname\\graphtemp\n"
129 "\\fi\n"
130 "\\expandafter\\setbox\\csname %s\\endcsname\n"
131 " =\\vtop{\\vskip 0pt\\hbox{%%\n",
132 graphname, graphname, graphname);
133 pen_size = -2.0;
136 void tex_output::finish_picture()
138 printf(" \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n"
139 " \\kern %.3fin\n"
140 " }%%\n"
141 "}%%\n",
142 height, width);
145 void tex_output::text(const position &center, text_piece *v, int n, double)
147 position c = transform(center);
148 for (int i = 0; i < n; i++)
149 if (v[i].text != 0 && *v[i].text != '\0') {
150 int j = 2*i - n + 1;
151 if (v[i].adj.v == ABOVE_ADJUST)
152 j--;
153 else if (v[i].adj.v == BELOW_ADJUST)
154 j++;
155 if (j == 0) {
156 printf(" \\graphtemp=.5ex\n"
157 " \\advance\\graphtemp by %.3fin\n", c.y);
159 else {
160 printf(" \\graphtemp=\\baselineskip\n"
161 " \\multiply\\graphtemp by %d\n"
162 " \\divide\\graphtemp by 2\n"
163 " \\advance\\graphtemp by .5ex\n"
164 " \\advance\\graphtemp by %.3fin\n",
165 j, c.y);
167 printf(" \\rlap{\\kern %.3fin\\lower\\graphtemp", c.x);
168 fputs("\\hbox to 0pt{", stdout);
169 if (v[i].adj.h != LEFT_ADJUST)
170 fputs("\\hss ", stdout);
171 fputs(v[i].text, stdout);
172 if (v[i].adj.h != RIGHT_ADJUST)
173 fputs("\\hss", stdout);
174 fputs("}}%\n", stdout);
178 void tex_output::point(const position &pos)
180 position p = transform(pos);
181 printf(" \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y));
184 void tex_output::line(const position &start, const position *v, int n,
185 const line_type &lt)
187 set_pen_size(lt.thickness);
188 point(start);
189 for (int i = 0; i < n; i++)
190 point(v[i]);
191 fputs(" \\special{", stdout);
192 switch(lt.type) {
193 case line_type::invisible:
194 fputs("ip", stdout);
195 break;
196 case line_type::solid:
197 fputs("fp", stdout);
198 break;
199 case line_type::dotted:
200 printf("dt %.3f", lt.dash_width/scale);
201 break;
202 case line_type::dashed:
203 printf("da %.3f", lt.dash_width/scale);
204 break;
206 fputs("}%\n", stdout);
209 void tex_output::polygon(const position *v, int n,
210 const line_type &lt, double fill)
212 if (fill >= 0.0) {
213 if (fill > 1.0)
214 fill = 1.0;
215 printf(" \\special{sh %.3f}%%\n", fill);
217 line(v[n-1], v, n, lt);
220 void tex_output::spline(const position &start, const position *v, int n,
221 const line_type &lt)
223 if (lt.type == line_type::invisible)
224 return;
225 set_pen_size(lt.thickness);
226 point(start);
227 for (int i = 0; i < n; i++)
228 point(v[i]);
229 fputs(" \\special{sp", stdout);
230 switch(lt.type) {
231 case line_type::solid:
232 break;
233 case line_type::dotted:
234 printf(" %.3f", -lt.dash_width/scale);
235 break;
236 case line_type::dashed:
237 printf(" %.3f", lt.dash_width/scale);
238 break;
239 case line_type::invisible:
240 assert(0);
242 fputs("}%\n", stdout);
245 void tex_output::solid_arc(const position &cent, double rad,
246 double start_angle, double end_angle,
247 const line_type &lt)
249 set_pen_size(lt.thickness);
250 position c = transform(cent);
251 printf(" \\special{ar %d %d %d %d %f %f}%%\n",
252 milliinches(c.x),
253 milliinches(c.y),
254 milliinches(rad/scale),
255 milliinches(rad/scale),
256 -end_angle,
257 (-end_angle > -start_angle) ? (double)M_PI * 2 - start_angle
258 : -start_angle);
261 void tex_output::arc(const position &start, const position &cent,
262 const position &end, const line_type &lt)
264 switch (lt.type) {
265 case line_type::invisible:
266 break;
267 case line_type::dashed:
268 dashed_arc(start, cent, end, lt);
269 break;
270 case line_type::dotted:
271 dotted_arc(start, cent, end, lt);
272 break;
273 case line_type::solid:
275 position c;
276 if (!compute_arc_center(start, cent, end, &c)) {
277 line(start, &end, 1, lt);
278 break;
280 solid_arc(c,
281 hypot(cent - start),
282 atan2(start.y - c.y, start.x - c.x),
283 atan2(end.y - c.y, end.x - c.x),
284 lt);
285 break;
290 void tex_output::circle(const position &cent, double rad,
291 const line_type &lt, double fill)
293 if (fill >= 0.0 && lt.type != line_type::solid) {
294 if (fill > 1.0)
295 fill = 1.0;
296 line_type ilt;
297 ilt.type = line_type::invisible;
298 ellipse(cent, position(rad*2.0, rad*2.0), ilt, fill);
300 switch (lt.type) {
301 case line_type::dashed:
302 dashed_circle(cent, rad, lt);
303 break;
304 case line_type::invisible:
305 break;
306 case line_type::solid:
307 ellipse(cent, position(rad*2.0,rad*2.0), lt, fill);
308 break;
309 case line_type::dotted:
310 dotted_circle(cent, rad, lt);
311 break;
312 default:
313 assert(0);
317 void tex_output::ellipse(const position &cent, const distance &dim,
318 const line_type &lt, double fill)
320 if (lt.type == line_type::invisible) {
321 if (fill < 0.0)
322 return;
324 else
325 set_pen_size(lt.thickness);
326 if (fill >= 0.0) {
327 if (fill > 1.0)
328 fill = 1.0;
329 printf(" \\special{sh %.3f}%%\n", fill);
331 position c = transform(cent);
332 switch (lt.type) {
333 case line_type::solid:
334 case line_type::invisible:
335 printf(" \\special{%s %d %d %d %d 0 6.28319}%%\n",
336 (lt.type == line_type::invisible ? "ia" : "ar"),
337 milliinches(c.x),
338 milliinches(c.y),
339 milliinches(dim.x/(2.0*scale)),
340 milliinches(dim.y/(2.0*scale)));
341 break;
342 case line_type::dashed:
343 dashed_ellipse(cent, dim / scale, lt);
344 break;
345 case line_type::dotted:
346 dotted_ellipse(cent, dim / scale, lt);
347 break;
348 default:
349 assert(0);
353 void tex_output::command(const char *s, const char *, int)
355 fputs(s, stdout);
356 putchar('%'); // avoid unwanted spaces
357 putchar('\n');
360 int tex_output::supports_filled_polygons()
362 return 1;
365 void tex_output::dot(const position &pos, const line_type &lt)
367 if (zero_length_line_flag) {
368 line_type slt = lt;
369 slt.type = line_type::solid;
370 line(pos, &pos, 1, slt);
372 else {
373 int dot_rad = int(lt.thickness*(1000.0/(72.0*2)) + .5);
374 if (dot_rad == 0)
375 dot_rad = 1;
376 position p = transform(pos);
377 printf(" \\special{sh 1}%%\n"
378 " \\special{ia %d %d %d %d 0 6.28319}%%\n",
379 milliinches(p.x), milliinches(p.y), dot_rad, dot_rad);
383 void tex_output::set_color(char *, char *)
385 /* not implemented yet */
388 void tex_output::reset_color()
390 /* not implemented yet */
393 char *tex_output::get_last_filled()
395 /* not implemented yet */
396 return NULL;
399 char *tex_output::get_outline_color()
401 /* not implemented yet */
402 return NULL;
405 class tpic_output
406 : public tex_output
408 int default_pen_size;
409 int prev_default_pen_size;
411 void set_pen_size(double ps);
413 public:
414 tpic_output();
415 void command(const char *, const char *, int);
418 tpic_output::tpic_output()
419 : default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE)
423 void tpic_output::command(const char *s, const char *filename, int lineno)
425 assert(s[0] == '.');
426 if (s[1] == 'p' && s[2] == 's' && (s[3] == '\0' || !csalpha(s[3]))) {
427 const char *p = s + 3;
428 while (csspace(*p))
429 p++;
430 if (*p == '\0') {
431 int temp = default_pen_size;
432 default_pen_size = prev_default_pen_size;
433 prev_default_pen_size = temp;
435 else {
436 char *ptr;
437 int temp = (int)strtol(p, &ptr, 10);
438 if (temp == 0 && ptr == p)
439 error_with_file_and_line(filename, lineno,
440 "argument to `.ps' not an integer");
441 else if (temp < 0)
442 error_with_file_and_line(filename, lineno,
443 "negative pen size");
444 else {
445 prev_default_pen_size = default_pen_size;
446 default_pen_size = temp;
450 else
451 printf("\\%s%%\n", s + 1);
454 void tpic_output::set_pen_size(double ps)
456 if (ps < 0.0)
457 printf(" \\special{pn %d}%%\n", default_pen_size);
458 else
459 tex_output::set_pen_size(ps);
462 output *make_tpic_output()
464 return new tpic_output;
467 #endif // TEX_SUPPORT
468 // s-it2-mode