/* Copyright (C) 1989, 1990, 1991 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. */
void print_object_list(object
*);
: type(solid
), thickness(1.0)
output::output() : desired_height(0.0), desired_width(0.0), args(0)
void output::set_desired_width_height(double wid
, double ht
)
void output::set_args(const char *s
)
if (s
== 0 || *s
== '\0')
void output::command(const char *, const char *, int)
void output::set_location(const char *, int)
int output::supports_filled_polygons()
void output::begin_block(const position
&, const position
&)
double output::compute_scale(double sc
, const position
&ll
, const position
&ur
)
if (desired_width
!= 0.0 || desired_height
!= 0.0) {
if (desired_width
!= 0.0) {
error("width specified for picture with zero width");
sc
= dim
.x
/desired_width
;
if (desired_height
!= 0.0) {
error("height specified for picture with zero height");
double tem
= dim
.y
/desired_height
;
return sc
== 0.0 ? 1.0 : sc
;
lookup_variable("maxpswid", &max_width
);
lookup_variable("maxpsht", &max_height
);
if ((max_width
> 0.0 && sdim
.x
> max_width
)
|| (max_height
> 0.0 && sdim
.y
> max_height
)) {
double xscale
= dim
.x
/max_width
;
double yscale
= dim
.y
/max_height
;
return xscale
> yscale
? xscale
: yscale
;
position::position(const place
&pl
)
*this = pl
.obj
->origin();
position::position() : x(0.0), y(0.0)
position::position(double a
, double b
) : x(a
), y(b
)
int operator==(const position
&a
, const position
&b
)
return a
.x
== b
.x
&& a
.y
== b
.y
;
int operator!=(const position
&a
, const position
&b
)
return a
.x
!= b
.x
|| a
.y
!= b
.y
;
position
&position::operator+=(const position
&a
)
position
&position::operator-=(const position
&a
)
position
&position::operator*=(double a
)
position
&position::operator/=(double a
)
position
operator-(const position
&a
)
return position(-a
.x
, -a
.y
);
position
operator+(const position
&a
, const position
&b
)
return position(a
.x
+ b
.x
, a
.y
+ b
.y
);
position
operator-(const position
&a
, const position
&b
)
return position(a
.x
- b
.x
, a
.y
- b
.y
);
position
operator/(const position
&a
, double n
)
return position(a
.x
/n
, a
.y
/n
);
position
operator*(const position
&a
, double n
)
return position(a
.x
*n
, a
.y
*n
);
double operator*(const position
&a
, const position
&b
)
return a
.x
*b
.x
+ a
.y
*b
.y
;
double hypot(const position
&a
)
void draw_arrow(const position
&pos
, const distance
&dir
,
const arrow_head_type
&aht
, const line_type
<
)
position
n(dir
.y
, -dir
.x
);
n
*= aht
.width
/(hyp
*2.0);
slt
.type
= line_type::solid
;
if (aht
.solid
&& out
->supports_filled_polygons()) {
// A value > 1 means fill with the current color.
out
->polygon(v
, 3, slt
, 2.0);
out
->line(pos
+ base
- n
, v
, 2, slt
);
object::object() : prev(0), next(0)
void object::move_by(const position
&)
void object::print_text()
void encompass(const position
&);
bounding_box::bounding_box()
void bounding_box::encompass(const position
&pos
)
void object::update_bounding_box(bounding_box
*)
position
object::origin()
return position(0.0,0.0);
position
object::north_east()
position
object::north_west()
position
object::south_east()
position
object::south_west()
position
object::center()
place
*object::find_label(const char *)
segment::segment(const position
&a
, int n
, segment
*p
)
: pos(a
), is_absolute(n
), next(p
)
text_item::text_item(char *t
, const char *fn
, int ln
)
: filename(fn
), lineno(ln
), text(t
), next(0)
object_spec::object_spec(object_type t
) : type(t
)
segment_width
= segment_height
= 0.0;
object_spec::~object_spec()
while (segment_list
!= 0) {
segment
*tem
= segment_list
;
segment_list
= segment_list
->next
;
class command_object
: public object
{
command_object(char *, const char *, int);
object_type
type() { return OTHER_OBJECT
; }
command_object::command_object(char *p
, const char *fn
, int ln
)
: s(p
), filename(fn
), lineno(ln
)
command_object::~command_object()
void command_object::print()
out
->command(s
, filename
, lineno
);
object
*make_command_object(char *s
, const char *fn
, int ln
)
return new command_object(s
, fn
, ln
);
class mark_object
: public object
{
object
*make_mark_object()
return new mark_object();
mark_object::mark_object()
object_type
mark_object::type()
object_list::object_list() : head(0), tail(0)
void object_list::append(object
*obj
)
obj
->next
= obj
->prev
= 0;
void object_list::wrap_up_block(object_list
*ol
)
for (object
*p
= tail
; p
&& p
->type() != MARK_OBJECT
; p
= p
->prev
)
: text(0), filename(0), lineno(-1)
text_piece::~text_piece()
class graphic_object
: public object
{
void add_text(text_item
*, int);
void set_thickness(double);
virtual void set_fill(double);
graphic_object::graphic_object() : ntext(0), text(0), aligned(0)
void graphic_object::set_dotted(double wid
)
lt
.type
= line_type::dotted
;
void graphic_object::set_dashed(double wid
)
lt
.type
= line_type::dashed
;
void graphic_object::set_thickness(double th
)
void graphic_object::set_fill(double)
void graphic_object::set_invisible()
lt
.type
= line_type::invisible
;
void graphic_object::add_text(text_item
*t
, int a
)
for (text_item
*p
= t
; p
; p
= p
->next
)
text
= new text_piece
[len
];
for (p
= t
, len
= 0; p
; p
= p
->next
, len
++) {
text
[len
].text
= p
->text
;
text
[len
].filename
= p
->filename
;
text
[len
].lineno
= p
->lineno
;
void graphic_object::print_text()
position
d(end() - start());
if (d
.x
!= 0.0 || d
.y
!= 0.0)
out
->text(center(), text
, ntext
, angle
);
graphic_object::~graphic_object()
class rectangle_object
: public graphic_object
{
rectangle_object(const position
&);
double width() { return dim
.x
; }
double height() { return dim
.y
; }
position
origin() { return cent
; }
position
center() { return cent
; }
position
north() { return position(cent
.x
, cent
.y
+ dim
.y
/2.0); }
position
south() { return position(cent
.x
, cent
.y
- dim
.y
/2.0); }
position
east() { return position(cent
.x
+ dim
.x
/2.0, cent
.y
); }
position
west() { return position(cent
.x
- dim
.x
/2.0, cent
.y
); }
position
north_east() { return position(cent
.x
+ dim
.x
/2.0, cent
.y
+ dim
.y
/2.0); }
position
north_west() { return position(cent
.x
- dim
.x
/2.0, cent
.y
+ dim
.y
/2.0); }
position
south_east() { return position(cent
.x
+ dim
.x
/2.0, cent
.y
- dim
.y
/2.0); }
position
south_west() { return position(cent
.x
- dim
.x
/2.0, cent
.y
- dim
.y
/2.0); }
void update_bounding_box(bounding_box
*);
void move_by(const position
&);
rectangle_object::rectangle_object(const position
&d
)
void rectangle_object::update_bounding_box(bounding_box
*p
)
p
->encompass(cent
- dim
/2.0);
p
->encompass(cent
+ dim
/2.0);
void rectangle_object::move_by(const position
&a
)
class closed_object
: public rectangle_object
{
closed_object(const position
&);
double fill
; // < 0 if not filled
closed_object::closed_object(const position
&pos
)
: rectangle_object(pos
), fill(-1.0)
void closed_object::set_fill(double f
)
class box_object
: public closed_object
{
box_object(const position
&, double);
object_type
type() { return BOX_OBJECT
; }
box_object::box_object(const position
&pos
, double r
)
: closed_object(pos
), rad(r
)
const double CHOP_FACTOR
= 1.0 - 1.0/M_SQRT2
;
position
box_object::north_east()
return position(cent
.x
+ dim
.x
/2.0 - CHOP_FACTOR
*rad
,
cent
.y
+ dim
.y
/2.0 - CHOP_FACTOR
*rad
);
position
box_object::north_west()
return position(cent
.x
- dim
.x
/2.0 + CHOP_FACTOR
*rad
,
cent
.y
+ dim
.y
/2.0 - CHOP_FACTOR
*rad
);
position
box_object::south_east()
return position(cent
.x
+ dim
.x
/2.0 - CHOP_FACTOR
*rad
,
cent
.y
- dim
.y
/2.0 + CHOP_FACTOR
*rad
);
position
box_object::south_west()
return position(cent
.x
- dim
.x
/2.0 + CHOP_FACTOR
*rad
,
cent
.y
- dim
.y
/2.0 + CHOP_FACTOR
*rad
);
if (lt
.type
== line_type::invisible
&& fill
< 0.0)
vec
[0] = cent
+ position(dim2
.x
, -dim2
.y
);
vec
[1] = cent
+ position(dim2
.x
, dim2
.y
);
vec
[2] = cent
+ position(-dim2
.x
, dim2
.y
);
vec
[3] = cent
+ position(-dim2
.x
, -dim2
.y
);
out
->polygon(vec
, 4, lt
, fill
);
out
->rounded_box(cent
, dim
, rad
, lt
, fill
);
graphic_object
*object_spec::make_box(position
*curpos
, direction
*dirp
)
static double last_box_height
;
static double last_box_width
;
static double last_box_radius
;
static int have_last_box
= 0;
if (!(flags
& HAS_HEIGHT
)) {
if ((flags
& IS_SAME
) && have_last_box
)
height
= last_box_height
;
lookup_variable("boxht", &height
);
if (!(flags
& HAS_WIDTH
)) {
if ((flags
& IS_SAME
) && have_last_box
)
lookup_variable("boxwid", &width
);
if (!(flags
& HAS_RADIUS
)) {
if ((flags
& IS_SAME
) && have_last_box
)
radius
= last_box_radius
;
lookup_variable("boxrad", &radius
);
last_box_height
= height
;
last_box_radius
= radius
;
box_object
*p
= new box_object(position(width
, height
), radius
);
if (!position_rectangle(p
, curpos
, dirp
)) {
// return non-zero for success
int object_spec::position_rectangle(rectangle_object
*p
,
position
*curpos
, direction
*dirp
)
dir
= *dirp
; // ignore any direction in attribute list
motion
.y
= p
->height()/2.0;
motion
.y
= -p
->height()/2.0;
motion
.x
= -p
->width()/2.0;
motion
.x
= p
->width()/2.0;
if (!with
->follow(here
, &offset
))
class block_object
: public rectangle_object
{
block_object(const position
&, const object_list
&ol
, PTABLE(place
) *t
);
place
*find_label(const char *);
void move_by(const position
&);
block_object::block_object(const position
&d
, const object_list
&ol
,
: oblist(ol
), tbl(t
), rectangle_object(d
)
block_object::~block_object()
void block_object::print()
out
->begin_block(south_west(), north_east());
print_object_list(oblist
.head
);
static void adjust_objectless_places(PTABLE(place
) *tbl
, const position
&a
)
// Adjust all the labels that aren't attached to objects.
PTABLE_ITERATOR(place
) iter(tbl
);
while (iter
.next(&key
, &pl
))
if (key
&& csupper(key
[0]) && pl
->obj
== 0) {
void block_object::move_by(const position
&a
)
for (object
*p
= oblist
.head
; p
; p
= p
->next
)
adjust_objectless_places(tbl
, a
);
place
*block_object::find_label(const char *name
)
return tbl
->lookup(name
);
object_type
block_object::type()
graphic_object
*object_spec::make_block(position
*curpos
, direction
*dirp
)
for (object
*p
= oblist
.head
; p
; p
= p
->next
)
p
->update_bounding_box(&bb
);
position m
= -(bb
.ll
+ bb
.ur
)/2.0;
for (object
*p
= oblist
.head
; p
; p
= p
->next
)
adjust_objectless_places(tbl
, m
);
block_object
*block
= new block_object(dim
, oblist
, tbl
);
if (!position_rectangle(block
, curpos
, dirp
)) {
oblist
.head
= oblist
.tail
= 0;
class text_object
: public rectangle_object
{
text_object(const position
&);
object_type
type() { return TEXT_OBJECT
; }
text_object::text_object(const position
&d
)
graphic_object
*object_spec::make_text(position
*curpos
, direction
*dirp
)
if (!(flags
& HAS_HEIGHT
)) {
lookup_variable("textht", &height
);
for (text_item
*t
= text
; t
; t
= t
->next
)
if (!(flags
& HAS_WIDTH
))
lookup_variable("textwid", &width
);
text_object
*p
= new text_object(position(width
, height
));
if (!position_rectangle(p
, curpos
, dirp
)) {
class ellipse_object
: public closed_object
{
ellipse_object(const position
&);
position
north_east() { return position(cent
.x
+ dim
.x
/(M_SQRT2
*2.0),
cent
.y
+ dim
.y
/(M_SQRT2
*2.0)); }
position
north_west() { return position(cent
.x
- dim
.x
/(M_SQRT2
*2.0),
cent
.y
+ dim
.y
/(M_SQRT2
*2.0)); }
position
south_east() { return position(cent
.x
+ dim
.x
/(M_SQRT2
*2.0),
cent
.y
- dim
.y
/(M_SQRT2
*2.0)); }
position
south_west() { return position(cent
.x
- dim
.x
/(M_SQRT2
*2.0),
cent
.y
- dim
.y
/(M_SQRT2
*2.0)); }
double radius() { return dim
.x
/2.0; }
object_type
type() { return ELLIPSE_OBJECT
; }
ellipse_object::ellipse_object(const position
&d
)
void ellipse_object::print()
if (lt
.type
== line_type::invisible
&& fill
< 0.0)
out
->ellipse(cent
, dim
, lt
, fill
);
graphic_object
*object_spec::make_ellipse(position
*curpos
, direction
*dirp
)
static double last_ellipse_height
;
static double last_ellipse_width
;
static int have_last_ellipse
= 0;
if (!(flags
& HAS_HEIGHT
)) {
if ((flags
& IS_SAME
) && have_last_ellipse
)
height
= last_ellipse_height
;
lookup_variable("ellipseht", &height
);
if (!(flags
& HAS_WIDTH
)) {
if ((flags
& IS_SAME
) && have_last_ellipse
)
width
= last_ellipse_width
;
lookup_variable("ellipsewid", &width
);
last_ellipse_width
= width
;
last_ellipse_height
= height
;
ellipse_object
*p
= new ellipse_object(position(width
, height
));
if (!position_rectangle(p
, curpos
, dirp
)) {
class circle_object
: public ellipse_object
{
object_type
type() { return CIRCLE_OBJECT
; }
circle_object::circle_object(double diam
)
: ellipse_object(position(diam
, diam
))
void circle_object::print()
if (lt
.type
== line_type::invisible
&& fill
< 0.0)
out
->circle(cent
, dim
.x
/2.0, lt
, fill
);
graphic_object
*object_spec::make_circle(position
*curpos
, direction
*dirp
)
static double last_circle_radius
;
static int have_last_circle
= 0;
if (!(flags
& HAS_RADIUS
)) {
if ((flags
& IS_SAME
) && have_last_circle
)
radius
= last_circle_radius
;
lookup_variable("circlerad", &radius
);
last_circle_radius
= radius
;
circle_object
*p
= new circle_object(radius
*2.0);
if (!position_rectangle(p
, curpos
, dirp
)) {
class move_object
: public graphic_object
{
move_object(const position
&s
, const position
&e
);
position
origin() { return en
; }
object_type
type() { return MOVE_OBJECT
; }
void update_bounding_box(bounding_box
*);
void move_by(const position
&);
move_object::move_object(const position
&s
, const position
&e
)
void move_object::update_bounding_box(bounding_box
*p
)
void move_object::move_by(const position
&a
)
graphic_object
*object_spec::make_move(position
*curpos
, direction
*dirp
)
static position last_move
;
static int have_last_move
= 0;
// No need to look at at since `at' attribute sets `from' attribute.
position startpos
= (flags
& HAS_FROM
) ? from
: *curpos
;
if (!(flags
& HAS_SEGMENT
)) {
if ((flags
&& IS_SAME
) && have_last_move
)
segment_pos
.y
= segment_height
;
segment_pos
.y
= -segment_height
;
segment_pos
.x
= -segment_width
;
segment_pos
.x
= segment_width
;
segment_list
= new segment(segment_pos
, segment_is_absolute
, segment_list
);
// Reverse the segment_list so that it's in forward order.
segment
*old
= segment_list
;
segment
*tem
= old
->next
;
old
->next
= segment_list
;
// Compute the end position.
position endpos
= startpos
;
for (segment
*s
= segment_list
; s
; s
= s
->next
)
last_move
= endpos
- startpos
;
move_object
*p
= new move_object(startpos
, endpos
);
class linear_object
: public graphic_object
{
linear_object(const position
&s
, const position
&e
);
position
start() { return strt
; }
position
end() { return en
; }
void move_by(const position
&);
void update_bounding_box(bounding_box
*) = 0;
void add_arrows(int at_start
, int at_end
, const arrow_head_type
&);
class line_object
: public linear_object
{
line_object(const position
&s
, const position
&e
, position
*, int);
position
origin() { return strt
; }
position
center() { return (strt
+ en
)/2.0; }
position
north() { return (en
.y
- strt
.y
) > 0 ? en
: strt
; }
position
south() { return (en
.y
- strt
.y
) < 0 ? en
: strt
; }
position
east() { return (en
.x
- strt
.x
) > 0 ? en
: strt
; }
position
west() { return (en
.x
- strt
.x
) < 0 ? en
: strt
; }
object_type
type() { return LINE_OBJECT
; }
void update_bounding_box(bounding_box
*);
void move_by(const position
&);
class arrow_object
: public line_object
{
arrow_object(const position
&, const position
&, position
*, int);
object_type
type() { return ARROW_OBJECT
; }
class spline_object
: public line_object
{
spline_object(const position
&, const position
&, position
*, int);
object_type
type() { return SPLINE_OBJECT
; }
void update_bounding_box(bounding_box
*);
linear_object::linear_object(const position
&s
, const position
&e
)
: strt(s
), en(e
), arrow_at_start(0), arrow_at_end(0)
void linear_object::move_by(const position
&a
)
void linear_object::add_arrows(int at_start
, int at_end
,
const arrow_head_type
&a
)
arrow_at_start
= at_start
;
line_object::line_object(const position
&s
, const position
&e
,
: v(p
), n(i
), linear_object(s
, e
)
void line_object::print()
if (lt
.type
== line_type::invisible
)
out
->line(strt
, v
, n
, lt
);
draw_arrow(strt
, strt
-v
[0], aht
, lt
);
draw_arrow(en
, v
[n
-1] - (n
> 1 ? v
[n
- 2] : strt
), aht
, lt
);
void line_object::update_bounding_box(bounding_box
*p
)
for (int i
= 0; i
< n
; i
++)
void line_object::move_by(const position
&pos
)
linear_object::move_by(pos
);
for (int i
= 0; i
< n
; i
++)
void spline_object::update_bounding_box(bounding_box
*p
)
[ the points for the Bezier cubic ]
(1-t)^3*p1 + 3*t*(t - 1)^2*p2 + 3*t^2*(1-t)*p3 + t^3*p4
[ the equation for the Bezier cubic ]
= .125*q1 + .75*q2 + .125*q3
for (int i
= 1; i
< n
; i
++)
p
->encompass((i
== 1 ? strt
: v
[i
-2])*.125 + v
[i
-1]*.75 + v
[i
]*.125);
arrow_object::arrow_object(const position
&s
, const position
&e
,
: line_object(s
, e
, p
, i
)
spline_object::spline_object(const position
&s
, const position
&e
,
: line_object(s
, e
, p
, i
)
void spline_object::print()
if (lt
.type
== line_type::invisible
)
out
->spline(strt
, v
, n
, lt
);
draw_arrow(strt
, strt
-v
[0], aht
, lt
);
draw_arrow(en
, v
[n
-1] - (n
> 1 ? v
[n
- 2] : strt
), aht
, lt
);
line_object::~line_object()
linear_object
*object_spec::make_line(position
*curpos
, direction
*dirp
)
static position last_line
;
static int have_last_line
= 0;
// No need to look at at since `at' attribute sets `from' attribute.
position startpos
= (flags
& HAS_FROM
) ? from
: *curpos
;
if (!(flags
& HAS_SEGMENT
)) {
if ((flags
& IS_SAME
) && (type
== LINE_OBJECT
|| type
== ARROW_OBJECT
)
segment_pos
.y
= segment_height
;
segment_pos
.y
= -segment_height
;
segment_pos
.x
= -segment_width
;
segment_pos
.x
= segment_width
;
segment_list
= new segment(segment_pos
, segment_is_absolute
, segment_list
);
// reverse the segment_list so that it's in forward order
segment
*old
= segment_list
;
segment
*tem
= old
->next
;
old
->next
= segment_list
;
// Absolutise all movements
position endpos
= startpos
;
for (segment
*s
= segment_list
; s
; s
= s
->next
, nsegments
++)
s
->is_absolute
= 1; // to avoid confusion
position
*v
= new position
[nsegments
];
for (s
= segment_list
; s
; s
= s
->next
, i
++)
if (flags
& IS_DEFAULT_CHOPPED
) {
lookup_variable("circlerad", &start_chop
);
if (flags
& IS_CHOPPED
) {
position start_chop_vec
, end_chop_vec
;
start_chop_vec
= v
[0] - startpos
;
start_chop_vec
*= start_chop
/ hypot(start_chop_vec
);
end_chop_vec
= (v
[nsegments
- 1]
- (nsegments
> 1 ? v
[nsegments
- 2] : startpos
));
end_chop_vec
*= end_chop
/ hypot(end_chop_vec
);
startpos
+= start_chop_vec
;
v
[nsegments
- 1] -= end_chop_vec
;
p
= new spline_object(startpos
, endpos
, v
, nsegments
);
p
= new arrow_object(startpos
, endpos
, v
, nsegments
);
p
= new line_object(startpos
, endpos
, v
, nsegments
);
last_line
= endpos
- startpos
;
class arc_object
: public linear_object
{
arc_object(int, const position
&, const position
&, const position
&);
position
origin() { return cent
; }
position
center() { return cent
; }
double radius() { return rad
; }
void update_bounding_box(bounding_box
*);
object_type
type() { return ARC_OBJECT
; }
void move_by(const position
&pos
);
arc_object::arc_object(int cw
, const position
&s
, const position
&e
,
: linear_object(s
, e
), clockwise(cw
), cent(c
)
void arc_object::move_by(const position
&pos
)
linear_object::move_by(pos
);
// we get arc corners from the corresponding circle
position
arc_object::north()
position
arc_object::south()
position
arc_object::east()
position
arc_object::west()
position
arc_object::north_east()
position
arc_object::north_west()
position
arc_object::south_east()
position
arc_object::south_west()
if (lt
.type
== line_type::invisible
)
out
->arc(en
, cent
, strt
, lt
);
out
->arc(strt
, cent
, en
, lt
);
position c
= cent
- strt
;
(clockwise
? position(c
.y
, -c
.x
) : position(-c
.y
, c
.x
)),
(clockwise
? position(e
.y
, -e
.x
) : position(-e
.y
, e
.x
)),
inline double max(double a
, double b
)
void arc_object::update_bounding_box(bounding_box
*p
)
position start_offset
= strt
- cent
;
if (start_offset
.x
== 0.0 && start_offset
.y
== 0.0)
position end_offset
= en
- cent
;
if (end_offset
.x
== 0.0 && end_offset
.y
== 0.0)
double start_quad
= atan2(start_offset
.y
, start_offset
.x
)/(M_PI
/2.0);
double end_quad
= atan2(end_offset
.y
, end_offset
.x
)/(M_PI
/2.0);
double temp
= start_quad
;
while (end_quad
<= start_quad
)
double radius
= max(hypot(start_offset
), hypot(end_offset
));
for (int q
= int(start_quad
) + 1; q
< end_quad
; q
++) {
p
->encompass(cent
+ offset
);
// We ignore the with attribute. The at attribute always refers to the center.
linear_object
*object_spec::make_arc(position
*curpos
, direction
*dirp
)
int cw
= (flags
& IS_CLOCKWISE
) != 0;
if (!(flags
& HAS_RADIUS
))
lookup_variable("arcrad", &radius
);
position
m(radius
, radius
);
if (dir
== DOWN_DIRECTION
|| dir
== LEFT_DIRECTION
)
if (dir
== DOWN_DIRECTION
|| dir
== RIGHT_DIRECTION
)
*dirp
= direction((dir
+ 3) % 4);
if (dir
== UP_DIRECTION
|| dir
== LEFT_DIRECTION
)
if (dir
== DOWN_DIRECTION
|| dir
== LEFT_DIRECTION
)
*dirp
= direction((dir
+ 1) % 4);
else if (startpos
== endpos
)
position h
= (endpos
- startpos
)/2.0;
// make the radius big enough
double alpha
= acos(d
/radius
);
double theta
= atan2(h
.y
, h
.x
);
centerpos
= position(cos(theta
), sin(theta
))*radius
+ startpos
;
arc_object
*p
= new arc_object(cw
, startpos
, endpos
, centerpos
);
graphic_object
*object_spec::make_linear(position
*curpos
, direction
*dirp
)
obj
= make_arc(curpos
, dirp
);
obj
= make_line(curpos
, dirp
);
&& (flags
& (HAS_LEFT_ARROW_HEAD
|HAS_RIGHT_ARROW_HEAD
)) == 0)
flags
|= HAS_RIGHT_ARROW_HEAD
;
if (obj
&& (flags
& (HAS_LEFT_ARROW_HEAD
|HAS_RIGHT_ARROW_HEAD
))) {
int at_start
= (flags
& HAS_LEFT_ARROW_HEAD
) != 0;
int at_end
= (flags
& HAS_RIGHT_ARROW_HEAD
) != 0;
lookup_variable("arrowht", &a
.height
);
lookup_variable("arrowwid", &a
.width
);
lookup_variable("arrowhead", &solid
);
obj
->add_arrows(at_start
, at_end
, a
);
object
*object_spec::make_object(position
*curpos
, direction
*dirp
)
obj
= make_block(curpos
, dirp
);
obj
= make_box(curpos
, dirp
);
obj
= make_text(curpos
, dirp
);
obj
= make_ellipse(curpos
, dirp
);
obj
= make_circle(curpos
, dirp
);
obj
= make_move(curpos
, dirp
);
obj
= make_linear(curpos
, dirp
);
if (flags
& IS_INVISIBLE
)
obj
->add_text(text
, (flags
& IS_ALIGNED
) != 0);
obj
->set_dotted(dash_width
);
else if (flags
& IS_DASHED
)
obj
->set_dashed(dash_width
);
if (flags
& HAS_THICKNESS
)
lookup_variable("linethick", &th
);
if (flags
& (IS_DEFAULT_FILLED
|IS_FILLED
)) {
if (flags
& IS_DEFAULT_FILLED
)
lookup_variable("fillval", &fill
);
error("bad fill value %1", fill
);
string_list::string_list(char *s
)
string_list::~string_list()
/* A path is used to hold the argument to the with attribute. For example,
`.nw' or `.A.s' or `.A'. The major operation on a path is to take a
place and follow the path through the place to place within the place.
Note that `.A.B.C.sw' will work. */
path::path(char *l
, corner c
)
label_list
= new string_list(l
);
string_list
*tem
= label_list
;
label_list
= label_list
->next
;
void path::append(corner c
)
void path::append(char *s
)
for (string_list
**p
= &label_list
; *p
; p
= &(*p
)->next
)
// return non-zero for success
int path::follow(const place
&pl
, place
*result
) const
for (string_list
*lb
= label_list
; lb
; lb
= lb
->next
)
if (p
->obj
== 0 || (p
= p
->obj
->find_label(lb
->str
)) == 0) {
lex_error("object does not contain a place `%1'", lb
->str
);
if (crn
== 0 || p
->obj
== 0)
position pos
= ((p
->obj
)->*(crn
))();
void print_object_list(object
*p
)
void print_picture(object
*obj
)
for (object
*p
= obj
; p
; p
= p
->next
)
p
->update_bounding_box(&bb
);
lookup_variable("scale", &scale
);
out
->start_picture(scale
, bb
.ll
, bb
.ur
);