2 * Copyright (c) 2014 - 2017 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
4 * Copyright (C) 1989 - 1992, 2000 - 2003, 2005 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
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
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.
23 #include "pic-config.h"
28 const double RELATIVE_THICKNESS
= -1.0;
29 const double BAD_THICKNESS
= -2.0;
32 : public common_output
34 virtual void simple_line(const position
&, const position
&) = 0;
35 virtual void simple_spline(const position
&, const position
*, int n
) = 0;
36 virtual void simple_arc(const position
&, const position
&,
37 const position
&) = 0;
38 virtual void simple_circle(int, const position
&, double rad
) = 0;
39 virtual void simple_ellipse(int, const position
&, const distance
&) = 0;
40 virtual void simple_polygon(int, const position
*, int) = 0;
41 virtual void line_thickness(double) = 0;
42 virtual void set_fill(double) = 0;
43 virtual void set_color(char *, char *) = 0;
44 virtual void reset_color() = 0;
45 virtual char *get_last_filled() = 0;
46 void dot(const position
&, const line_type
&) = 0;
49 void start_picture(double sc
, const position
&ll
, const position
&ur
) = 0;
50 void finish_picture() = 0;
51 void text(const position
&, text_piece
*, int, double) = 0;
52 void line(const position
&, const position
*, int n
,
54 void polygon(const position
*, int n
,
55 const line_type
&, double);
56 void spline(const position
&, const position
*, int n
,
58 void arc(const position
&, const position
&, const position
&,
60 void circle(const position
&, double rad
, const line_type
&, double);
61 void ellipse(const position
&, const distance
&, const line_type
&, double);
62 int supports_filled_polygons();
65 int simple_output::supports_filled_polygons()
67 return driver_extension_flag
!= 0;
70 void simple_output::arc(const position
&start
, const position
¢
,
71 const position
&end
, const line_type
<
)
74 case line_type::solid
:
75 line_thickness(lt
.thickness
);
76 simple_arc(start
, cent
, end
);
78 case line_type::invisible
:
80 case line_type::dashed
:
81 dashed_arc(start
, cent
, end
, lt
);
83 case line_type::dotted
:
84 dotted_arc(start
, cent
, end
, lt
);
89 void simple_output::line(const position
&start
, const position
*v
, int n
,
93 line_thickness(lt
.thickness
);
94 for (int i
= 0; i
< n
; i
++) {
96 case line_type::solid
:
97 simple_line(pos
, v
[i
]);
99 case line_type::dotted
:
101 distance
vec(v
[i
] - pos
);
102 double dist
= hypot(vec
);
103 int ndots
= int(dist
/lt
.dash_width
+ .5);
107 vec
/= double(ndots
);
108 for (int j
= 0; j
<= ndots
; j
++)
109 dot(pos
+ vec
*j
, lt
);
113 case line_type::dashed
:
115 distance
vec(v
[i
] - pos
);
116 double dist
= hypot(vec
);
117 if (dist
<= lt
.dash_width
*2.0)
118 simple_line(pos
, v
[i
]);
120 int ndashes
= int((dist
- lt
.dash_width
)/(lt
.dash_width
*2.0) + .5);
121 distance dash_vec
= vec
*(lt
.dash_width
/dist
);
122 double dash_gap
= (dist
- lt
.dash_width
)/ndashes
;
123 distance dash_gap_vec
= vec
*(dash_gap
/dist
);
124 for (int j
= 0; j
<= ndashes
; j
++) {
125 position
s(pos
+ dash_gap_vec
*j
);
126 simple_line(s
, s
+ dash_vec
);
131 case line_type::invisible
:
140 void simple_output::spline(const position
&start
, const position
*v
, int n
,
143 line_thickness(lt
.thickness
);
144 simple_spline(start
, v
, n
);
147 void simple_output::polygon(const position
*v
, int n
,
148 const line_type
<
, double fill
)
150 if (driver_extension_flag
&& ((fill
>= 0.0) || (get_last_filled() != 0))) {
151 if (get_last_filled() == 0)
153 simple_polygon(1, v
, n
);
155 if (lt
.type
== line_type::solid
&& driver_extension_flag
) {
156 line_thickness(lt
.thickness
);
157 simple_polygon(0, v
, n
);
159 else if (lt
.type
!= line_type::invisible
) {
160 line_thickness(lt
.thickness
);
161 line(v
[n
- 1], v
, n
, lt
);
165 void simple_output::circle(const position
¢
, double rad
,
166 const line_type
<
, double fill
)
168 if (driver_extension_flag
&& ((fill
>= 0.0) || (get_last_filled() != 0))) {
169 if (get_last_filled() == 0)
171 simple_circle(1, cent
, rad
);
173 line_thickness(lt
.thickness
);
175 case line_type::invisible
:
177 case line_type::dashed
:
178 dashed_circle(cent
, rad
, lt
);
180 case line_type::dotted
:
181 dotted_circle(cent
, rad
, lt
);
183 case line_type::solid
:
184 simple_circle(0, cent
, rad
);
191 void simple_output::ellipse(const position
¢
, const distance
&dim
,
192 const line_type
<
, double fill
)
194 if (driver_extension_flag
&& ((fill
>= 0.0) || (get_last_filled() != 0))) {
195 if (get_last_filled() == 0)
197 simple_ellipse(1, cent
, dim
);
199 if (lt
.type
!= line_type::invisible
)
200 line_thickness(lt
.thickness
);
202 case line_type::invisible
:
204 case line_type::dotted
:
205 dotted_ellipse(cent
, dim
, lt
);
207 case line_type::dashed
:
208 dashed_ellipse(cent
, dim
, lt
);
210 case line_type::solid
:
211 simple_ellipse(0, cent
, dim
);
219 : public simple_output
221 const char *last_filename
;
225 double last_line_thickness
;
227 char *last_filled
; // color
228 char *last_outlined
; // color
233 void start_picture(double, const position
&ll
, const position
&ur
);
234 void finish_picture();
235 void text(const position
&, text_piece
*, int, double);
236 void dot(const position
&, const line_type
&);
237 void command(const char *, const char *, int);
238 void set_location(const char *, int);
239 void simple_line(const position
&, const position
&);
240 void simple_spline(const position
&, const position
*, int n
);
241 void simple_arc(const position
&, const position
&, const position
&);
242 void simple_circle(int, const position
&, double rad
);
243 void simple_ellipse(int, const position
&, const distance
&);
244 void simple_polygon(int, const position
*, int);
245 void line_thickness(double p
);
246 void set_fill(double);
247 void set_color(char *, char *);
249 char *get_last_filled();
250 char *get_outline_color();
251 position
transform(const position
&);
254 output
*make_troff_output()
256 return new troff_output
;
259 troff_output::troff_output()
260 : last_filename(0), last_line_thickness(BAD_THICKNESS
),
261 last_fill(-1.0), last_filled(0), last_outlined(0)
265 troff_output::~troff_output()
269 inline position
troff_output::transform(const position
&pos
)
271 return position((pos
.x
- upper_left
.x
)/scale
,
272 (upper_left
.y
- pos
.y
)/scale
);
275 void troff_output::start_picture(double sc
,
276 const position
&ll
, const position
&ur
)
280 scale
= compute_scale(sc
, ll
, ur
);
281 height
= (ur
.y
- ll
.y
)/scale
;
282 double width
= (ur
.x
- ll
.x
)/scale
;
283 printf(".PS %.3fi %.3fi", height
, width
);
285 printf(" %s\n", args
);
288 printf(".\\\" %g %g %g %g\n", ll
.x
, ll
.y
, ur
.x
, ur
.y
);
289 printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height
, width
, 0.0);
290 printf(".nr " FILL_REG
" \\n(.u\n.nf\n");
291 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 1\n");
292 // This guarantees that if the picture is used in a diversion it will
293 // have the right width.
294 printf("\\h'%.3fi'\n.sp -1\n", width
);
297 void troff_output::finish_picture()
299 line_thickness(BAD_THICKNESS
);
300 last_fill
= -1.0; // force it to be reset for each picture
303 printf(".sp %.3fi+1\n", height
);
304 printf(".if \\n(" FILL_REG
" .fi\n");
306 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 0\n");
307 // this is a little gross
308 set_location(current_filename
, current_lineno
);
309 fputs(flyback_flag
? ".PF\n" : ".PE\n", stdout
);
312 void troff_output::command(const char *s
,
313 const char *filename
, int lineno
)
316 set_location(filename
, lineno
);
321 void troff_output::simple_circle(int filled
, const position
¢
, double rad
)
323 position c
= transform(cent
);
330 (filled
? 'C' : 'c'),
334 void troff_output::simple_ellipse(int filled
, const position
¢
,
337 position c
= transform(cent
);
340 "\\D'%c %.3fi %.3fi'"
342 c
.x
- dim
.x
/(2.0*scale
),
344 (filled
? 'E' : 'e'),
345 dim
.x
/scale
, dim
.y
/scale
);
348 void troff_output::simple_arc(const position
&start
, const distance
¢
,
351 position s
= transform(start
);
352 position c
= transform(cent
);
354 distance ev
= transform(end
) - c
;
357 "\\D'a %.3fi %.3fi %.3fi %.3fi'"
359 s
.x
, s
.y
, cv
.x
, cv
.y
, ev
.x
, ev
.y
);
362 void troff_output::simple_line(const position
&start
, const position
&end
)
364 position s
= transform(start
);
365 distance ev
= transform(end
) - s
;
370 s
.x
, s
.y
, ev
.x
, ev
.y
);
373 void troff_output::simple_spline(const position
&start
,
374 const position
*v
, int n
)
376 position pos
= transform(start
);
380 fputs("\\D'~ ", stdout
);
381 for (int i
= 0; i
< n
; i
++) {
382 position temp
= transform(v
[i
]);
383 distance d
= temp
- pos
;
387 printf("%.3fi %.3fi", d
.x
, d
.y
);
389 printf("'\n.sp -1\n");
394 void troff_output::simple_polygon(int filled
, const position
*v
, int n
)
396 position pos
= transform(v
[0]);
400 printf("\\D'%c ", (filled
? 'P' : 'p'));
401 for (int i
= 1; i
< n
; i
++) {
402 position temp
= transform(v
[i
]);
403 distance d
= temp
- pos
;
407 printf("%.3fi %.3fi", d
.x
, d
.y
);
409 printf("'\n.sp -1\n");
412 const double TEXT_AXIS
= 0.22; // in ems
414 static const char *choose_delimiter(const char *text
)
416 if (strchr(text
, '\'') == 0)
422 void troff_output::text(const position
¢er
, text_piece
*v
, int n
,
425 line_thickness(BAD_THICKNESS
); // the text might use lines (eg in equations)
427 if (driver_extension_flag
&& ang
!= 0.0) {
429 position c
= transform(center
);
430 printf(".if \\n(" L_D_PS_REG
" \\{\\\n"
433 "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
436 c
.x
, c
.y
, -ang
*180.0/M_PI
);
438 for (int i
= 0; i
< n
; i
++)
439 if (v
[i
].text
!= 0 && *v
[i
].text
!= '\0') {
440 position c
= transform(center
);
441 if (v
[i
].filename
!= 0)
442 set_location(v
[i
].filename
, v
[i
].lineno
);
443 printf("\\h'%.3fi", c
.x
);
444 const char *delim
= choose_delimiter(v
[i
].text
);
445 if (v
[i
].adj
.h
== RIGHT_ADJUST
)
446 printf("-\\w%s%s%su", delim
, v
[i
].text
, delim
);
447 else if (v
[i
].adj
.h
!= LEFT_ADJUST
)
448 printf("-(\\w%s%s%su/2u)", delim
, v
[i
].text
, delim
);
450 printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
455 if (v
[i
].adj
.v
== ABOVE_ADJUST
)
457 else if (v
[i
].adj
.v
== BELOW_ADJUST
)
460 fputs(v
[i
].text
, stdout
);
461 fputs("\n.sp -1\n", stdout
);
464 printf(".if '\\n(" L_D_PS_REG
" \\{\\\n"
465 "\\X'ps: exec grestore'\n.sp -1\n"
469 void troff_output::line_thickness(double p
)
472 p
= RELATIVE_THICKNESS
;
473 if (driver_extension_flag
&& p
!= last_line_thickness
) {
474 printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p
, -p
);
475 last_line_thickness
= p
;
479 void troff_output::set_fill(double f
)
481 if (driver_extension_flag
&& f
!= last_fill
) {
482 // \D'Fg ...' emits a node only in compatibility mode,
483 // thus we add a dummy node
484 printf("\\&\\D'Fg %.3f'\n.sp -1\n", 1.0 - f
);
494 void troff_output::set_color(char *color_fill
, char *color_outlined
)
496 if (driver_extension_flag
) {
497 if (last_filled
|| last_outlined
) {
500 // .gcolor and .fcolor emit a node in compatibility mode only,
501 // but that won't work anyway
503 printf(".fcolor %s\n", color_fill
);
504 last_filled
= strsave(color_fill
);
506 if (color_outlined
) {
507 printf(".gcolor %s\n", color_outlined
);
508 last_outlined
= strsave(color_outlined
);
513 void troff_output::reset_color()
515 if (driver_extension_flag
) {
518 a_delete last_filled
;
523 a_delete last_outlined
;
529 char *troff_output::get_last_filled()
534 char *troff_output::get_outline_color()
536 return last_outlined
;
539 const double DOT_AXIS
= .044;
541 void troff_output::dot(const position
¢
, const line_type
<
)
543 if (driver_extension_flag
) {
544 line_thickness(lt
.thickness
);
545 simple_line(cent
, cent
);
548 position c
= transform(cent
);
549 printf("\\h'%.3fi-(\\w'.'u/2u)'"
558 void troff_output::set_location(const char *s
, int n
)
560 if (last_filename
!= 0 && strcmp(s
, last_filename
) == 0)
561 printf(".lf %d\n", n
);
563 printf(".lf %d %s\n", n
, s
);