/* Copyright (C) 1989, 1990 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp)
This file is part of groff.
groff is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 1, or (at your option) any later
groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
You should have received a copy of the GNU General Public License along
with groff; see the file LICENSE. If not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
const double RELATIVE_THICKNESS
= -1.0;
const double BAD_THICKNESS
= -2.0;
class simple_output
: public common_output
{
virtual void simple_line(const position
&, const position
&) = 0;
virtual void simple_spline(const position
&, const position
*, int n
) = 0;
virtual void simple_arc(const position
&, const position
&,
virtual void simple_circle(int, const position
&, double rad
) = 0;
virtual void simple_ellipse(int, const position
&, const distance
&) = 0;
virtual void simple_polygon(int, const position
*, int) = 0;
virtual void line_thickness(double) = 0;
virtual void set_fill(double) = 0;
void dot(const position
&, const line_type
&) = 0;
void start_picture(double sc
, const position
&ll
, const position
&ur
) = 0;
void finish_picture() = 0;
void text(const position
&, text_piece
*, int, double) = 0;
void line(const position
&, const position
*, int n
,
void polygon(const position
*, int n
,
const line_type
&, double);
void spline(const position
&, const position
*, int n
,
void arc(const position
&, const position
&, const position
&,
void circle(const position
&, double rad
, const line_type
&, double);
void ellipse(const position
&, const distance
&, const line_type
&, double);
int supports_filled_polygons();
int simple_output::supports_filled_polygons()
return driver_extension_flag
!= 0;
void simple_output::arc(const position
&start
, const position
¢
,
const position
&end
, const line_type
<
)
line_thickness(lt
.thickness
);
simple_arc(start
, cent
, end
);
case line_type::invisible
:
dashed_arc(start
, cent
, end
, lt
);
dotted_arc(start
, cent
, end
, lt
);
void simple_output::line(const position
&start
, const position
*v
, int n
,
line_thickness(lt
.thickness
);
for (int i
= 0; i
< n
; i
++) {
distance
vec(v
[i
] - pos
);
double dist
= hypot(vec
);
int ndots
= int(dist
/lt
.dash_width
+ .5);
for (int j
= 0; j
<= ndots
; j
++)
distance
vec(v
[i
] - pos
);
double dist
= hypot(vec
);
if (dist
<= lt
.dash_width
*2.0)
int ndashes
= int((dist
- lt
.dash_width
)/(lt
.dash_width
*2.0) + .5);
distance dash_vec
= vec
*(lt
.dash_width
/dist
);
double dash_gap
= (dist
- lt
.dash_width
)/ndashes
;
distance dash_gap_vec
= vec
*(dash_gap
/dist
);
for (int j
= 0; j
<= ndashes
; j
++) {
position
s(pos
+ dash_gap_vec
*j
);
simple_line(s
, s
+ dash_vec
);
case line_type::invisible
:
void simple_output::spline(const position
&start
, const position
*v
, int n
,
line_thickness(lt
.thickness
);
simple_spline(start
, v
, n
);
void simple_output::polygon(const position
*v
, int n
,
const line_type
<
, double fill
)
if (driver_extension_flag
) {
if (lt
.type
== line_type::solid
&& driver_extension_flag
) {
line_thickness(lt
.thickness
);
else if (lt
.type
!= line_type::invisible
) {
line_thickness(lt
.thickness
);
line(v
[n
- 1], v
, n
, lt
);
void simple_output::circle(const position
¢
, double rad
,
const line_type
<
, double fill
)
if (driver_extension_flag
&& fill
>= 0.0) {
simple_circle(1, cent
, rad
);
line_thickness(lt
.thickness
);
case line_type::invisible
:
dashed_circle(cent
, rad
, lt
);
dotted_circle(cent
, rad
, lt
);
simple_circle(0, cent
, rad
);
void simple_output::ellipse(const position
¢
, const distance
&dim
,
const line_type
<
, double fill
)
if (driver_extension_flag
&& fill
>= 0.0) {
simple_ellipse(1, cent
, dim
);
if (lt
.type
!= line_type::invisible
)
line_thickness(lt
.thickness
);
case line_type::invisible
:
simple_ellipse(0, cent
, dim
);
class troff_output
: public simple_output
{
const char *last_filename
;
double last_line_thickness
;
void start_picture(double, const position
&ll
, const position
&ur
);
void text(const position
&, text_piece
*, int, double);
void dot(const position
&, const line_type
&);
void command(const char *, const char *, int);
void set_location(const char *, int);
void simple_line(const position
&, const position
&);
void simple_spline(const position
&, const position
*, int n
);
void simple_arc(const position
&, const position
&, const position
&);
void simple_circle(int, const position
&, double rad
);
void simple_ellipse(int, const position
&, const distance
&);
void simple_polygon(int, const position
*, int);
void line_thickness(double p
);
position
transform(const position
&);
output
*make_troff_output()
troff_output::troff_output()
: last_filename(0), last_line_thickness(BAD_THICKNESS
), last_fill(-1.0)
troff_output::~troff_output()
inline position
troff_output::transform(const position
&pos
)
return position((pos
.x
- upper_left
.x
)/scale
,
(upper_left
.y
- pos
.y
)/scale
);
// if this register is defined, geqn won't produce `\x's
#define EQN_NO_EXTRA_SPACE_REG "0x"
void troff_output::start_picture(double sc
,
const position
&ll
, const position
&ur
)
scale
= compute_scale(sc
, ll
, ur
);
height
= (ur
.y
- ll
.y
)/scale
;
double width
= (ur
.x
- ll
.x
)/scale
;
printf(".PS %.3fi %.3fi", height
, width
);
printf(".\\\" %g %g %g %g\n", ll
.x
, ll
.y
, ur
.x
, ur
.y
);
printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height
, width
, 0.0);
printf(".nr " FILL_REG
" \\n(.u\n.nf\n");
printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 1\n");
void troff_output::finish_picture()
line_thickness(BAD_THICKNESS
);
last_fill
= -1.0; // force it to be reset for each picture
printf(".sp %.3fi+1\n", height
);
printf(".if \\n(" FILL_REG
" .fi\n");
printf(".rr " EQN_NO_EXTRA_SPACE_REG
"\n");
// this is a little gross
set_location(current_filename
, current_lineno
);
fputs(flyback_flag
? ".PF\n" : ".PE\n", stdout
);
void troff_output::command(const char *s
,
const char *filename
, int lineno
)
set_location(filename
, lineno
);
void troff_output::simple_circle(int filled
, const position
¢
, double rad
)
position c
= transform(cent
);
void troff_output::simple_ellipse(int filled
, const position
¢
,
position c
= transform(cent
);
dim
.x
/scale
, dim
.y
/scale
);
void troff_output::simple_arc(const position
&start
, const distance
¢
,
position s
= transform(start
);
position c
= transform(cent
);
distance ev
= transform(end
) - c
;
"\\D'a%.3fi %.3fi %.3fi %.3fi'"
s
.x
, s
.y
, cv
.x
, cv
.y
, ev
.x
, ev
.y
);
void troff_output::simple_line(const position
&start
, const position
&end
)
position s
= transform(start
);
distance ev
= transform(end
) - s
;
void troff_output::simple_spline(const position
&start
,
const position
*v
, int n
)
position pos
= transform(start
);
for (int i
= 0; i
< n
; i
++) {
position temp
= transform(v
[i
]);
printf("%.3fi %.3fi", v
.x
, v
.y
);
void troff_output::simple_polygon(int filled
, const position
*v
, int n
)
position pos
= transform(v
[0]);
printf("\\D'%c", (filled
? 'P' : 'p'));
for (int i
= 1; i
< n
; i
++) {
position temp
= transform(v
[i
]);
printf("%.3fi %.3fi", v
.x
, v
.y
);
const double TEXT_AXIS
= 0.22; // in ems
static const char *choose_delimiter(const char *text
)
if (strchr(text
, '\'') == 0)
void troff_output::text(const position
¢er
, text_piece
*v
, int n
, double)
for (int i
= 0; i
< n
; i
++)
if (v
[i
].text
!= 0 && *v
[i
].text
!= '\0') {
position c
= transform(center
);
set_location(v
[i
].filename
, v
[i
].lineno
);
printf("\\h'%.3fi", c
.x
);
const char *delim
= choose_delimiter(v
[i
].text
);
if (v
[i
].adj
.h
== RIGHT_ADJUST
)
printf("-\\w%s%s%su", delim
, v
[i
].text
, delim
);
else if (v
[i
].adj
.h
!= LEFT_ADJUST
)
printf("-(\\w%s%s%su/2u)", delim
, v
[i
].text
, delim
);
printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
if (v
[i
].adj
.v
== ABOVE_ADJUST
)
else if (v
[i
].adj
.v
== BELOW_ADJUST
)
fputs(v
[i
].text
, stdout
);
fputs("\n.sp -1\n", stdout
);
void troff_output::line_thickness(double p
)
if (driver_extension_flag
&& p
!= last_line_thickness
) {
printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p
, -p
);
void troff_output::set_fill(double f
)
if (driver_extension_flag
&& f
!= last_fill
) {
printf("\\D'f %du'\\h'%du'\n.sp -1\n", int(f
*FILL_MAX
), -int(f
*FILL_MAX
));
const double DOT_AXIS
= .044;
void troff_output::dot(const position
¢
, const line_type
<
)
if (zero_length_line_flag
) {
line_thickness(lt
.thickness
);
position c
= transform(cent
);
printf("\\h'%.3fi-(\\w'.'u/2u)'"
void troff_output::set_location(const char *s
, int n
)
if (last_filename
!= 0 && strcmp(s
, last_filename
) == 0)
printf(".lf %d %s\n", n
, s
);
class grops_output
: public troff_output
{
void text(const position
&, text_piece
*, int, double);
grops_output::grops_output()
grops_output::~grops_output()
output
*make_grops_output()
void grops_output::text(const position
¢er
, text_piece
*v
, int n
,
position c
= transform(center
);
c
.x
, c
.y
, -ang
*180.0/M_PI
);
"\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
c
.x
, c
.y
, -ang
*180.0/M_PI
);
troff_output::text(center
, v
, n
, ang
);
printf("\\X'ps: end rotate'\n.sp -1\n");
printf("\\X'ps: exec grestore'\n.sp -1\n");