165837Sbostic // -*- C++ -*-
265837Sbostic /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
365837Sbostic Written by James Clark (jjc@jclark.com)
465837Sbostic
565837Sbostic This file is part of groff.
665837Sbostic
765837Sbostic groff is free software; you can redistribute it and/or modify it under
865837Sbostic the terms of the GNU General Public License as published by the Free
965837Sbostic Software Foundation; either version 2, or (at your option) any later
1065837Sbostic version.
1165837Sbostic
1265837Sbostic groff is distributed in the hope that it will be useful, but WITHOUT ANY
1365837Sbostic WARRANTY; without even the implied warranty of MERCHANTABILITY or
1465837Sbostic FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1565837Sbostic for more details.
1665837Sbostic
1765837Sbostic You should have received a copy of the GNU General Public License along
1865837Sbostic with groff; see the file COPYING. If not, write to the Free Software
1965837Sbostic Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
2065837Sbostic
2165837Sbostic #include "pic.h"
2265837Sbostic #include "ptable.h"
2365837Sbostic #include "object.h"
2465837Sbostic
2565837Sbostic void print_object_list(object *);
2665837Sbostic
line_type()2765837Sbostic line_type::line_type()
2865837Sbostic : type(solid), thickness(1.0)
2965837Sbostic {
3065837Sbostic }
3165837Sbostic
output()3265837Sbostic output::output() : desired_height(0.0), desired_width(0.0), args(0)
3365837Sbostic {
3465837Sbostic }
3565837Sbostic
~output()3665837Sbostic output::~output()
3765837Sbostic {
3865837Sbostic a_delete args;
3965837Sbostic }
4065837Sbostic
set_desired_width_height(double wid,double ht)4165837Sbostic void output::set_desired_width_height(double wid, double ht)
4265837Sbostic {
4365837Sbostic desired_width = wid;
4465837Sbostic desired_height = ht;
4565837Sbostic }
4665837Sbostic
set_args(const char * s)4765837Sbostic void output::set_args(const char *s)
4865837Sbostic {
4965837Sbostic a_delete args;
5065837Sbostic if (s == 0 || *s == '\0')
5165837Sbostic args = 0;
5265837Sbostic else
5365837Sbostic args = strsave(s);
5465837Sbostic }
5565837Sbostic
command(const char *,const char *,int)5665837Sbostic void output::command(const char *, const char *, int)
5765837Sbostic {
5865837Sbostic }
5965837Sbostic
set_location(const char *,int)6065837Sbostic void output::set_location(const char *, int)
6165837Sbostic {
6265837Sbostic }
6365837Sbostic
supports_filled_polygons()6465837Sbostic int output::supports_filled_polygons()
6565837Sbostic {
6665837Sbostic return 0;
6765837Sbostic }
6865837Sbostic
begin_block(const position &,const position &)6965837Sbostic void output::begin_block(const position &, const position &)
7065837Sbostic {
7165837Sbostic }
7265837Sbostic
end_block()7365837Sbostic void output::end_block()
7465837Sbostic {
7565837Sbostic }
7665837Sbostic
compute_scale(double sc,const position & ll,const position & ur)7765837Sbostic double output::compute_scale(double sc, const position &ll, const position &ur)
7865837Sbostic {
7965837Sbostic distance dim = ur - ll;
8065837Sbostic if (desired_width != 0.0 || desired_height != 0.0) {
8165837Sbostic sc = 0.0;
8265837Sbostic if (desired_width != 0.0) {
8365837Sbostic if (dim.x == 0.0)
8465837Sbostic error("width specified for picture with zero width");
8565837Sbostic else
8665837Sbostic sc = dim.x/desired_width;
8765837Sbostic }
8865837Sbostic if (desired_height != 0.0) {
8965837Sbostic if (dim.y == 0.0)
9065837Sbostic error("height specified for picture with zero height");
9165837Sbostic else {
9265837Sbostic double tem = dim.y/desired_height;
9365837Sbostic if (tem > sc)
9465837Sbostic sc = tem;
9565837Sbostic }
9665837Sbostic }
9765837Sbostic return sc == 0.0 ? 1.0 : sc;
9865837Sbostic }
9965837Sbostic else {
10065837Sbostic if (sc <= 0.0)
10165837Sbostic sc = 1.0;
10265837Sbostic distance sdim = dim/sc;
10365837Sbostic double max_width = 0.0;
10465837Sbostic lookup_variable("maxpswid", &max_width);
10565837Sbostic double max_height = 0.0;
10665837Sbostic lookup_variable("maxpsht", &max_height);
10765837Sbostic if ((max_width > 0.0 && sdim.x > max_width)
10865837Sbostic || (max_height > 0.0 && sdim.y > max_height)) {
10965837Sbostic double xscale = dim.x/max_width;
11065837Sbostic double yscale = dim.y/max_height;
11165837Sbostic return xscale > yscale ? xscale : yscale;
11265837Sbostic }
11365837Sbostic else
11465837Sbostic return sc;
11565837Sbostic }
11665837Sbostic }
11765837Sbostic
position(const place & pl)11865837Sbostic position::position(const place &pl)
11965837Sbostic {
12065837Sbostic if (pl.obj != 0) {
12165837Sbostic // Use two statements to work around bug in SGI C++.
12265837Sbostic object *tem = pl.obj;
12365837Sbostic *this = tem->origin();
12465837Sbostic }
12565837Sbostic else {
12665837Sbostic x = pl.x;
12765837Sbostic y = pl.y;
12865837Sbostic }
12965837Sbostic }
13065837Sbostic
position()13165837Sbostic position::position() : x(0.0), y(0.0)
13265837Sbostic {
13365837Sbostic }
13465837Sbostic
position(double a,double b)13565837Sbostic position::position(double a, double b) : x(a), y(b)
13665837Sbostic {
13765837Sbostic }
13865837Sbostic
139*65838Sbostic /*
140*65838Sbostic * XXX workaround for gcc 2.3.3 initializer bug.
141*65838Sbostic * From: Chris Torek <torek@BSDI.COM>
142*65838Sbostic */
posref(position p)143*65838Sbostic position &posref(position p) { return p; }
14465837Sbostic
145*65838Sbostic
operator ==(const position & a,const position & b)14665837Sbostic int operator==(const position &a, const position &b)
14765837Sbostic {
14865837Sbostic return a.x == b.x && a.y == b.y;
14965837Sbostic }
15065837Sbostic
operator !=(const position & a,const position & b)15165837Sbostic int operator!=(const position &a, const position &b)
15265837Sbostic {
15365837Sbostic return a.x != b.x || a.y != b.y;
15465837Sbostic }
15565837Sbostic
operator +=(const position & a)15665837Sbostic position &position::operator+=(const position &a)
15765837Sbostic {
15865837Sbostic x += a.x;
15965837Sbostic y += a.y;
16065837Sbostic return *this;
16165837Sbostic }
16265837Sbostic
operator -=(const position & a)16365837Sbostic position &position::operator-=(const position &a)
16465837Sbostic {
16565837Sbostic x -= a.x;
16665837Sbostic y -= a.y;
16765837Sbostic return *this;
16865837Sbostic }
16965837Sbostic
operator *=(double a)17065837Sbostic position &position::operator*=(double a)
17165837Sbostic {
17265837Sbostic x *= a;
17365837Sbostic y *= a;
17465837Sbostic return *this;
17565837Sbostic }
17665837Sbostic
operator /=(double a)17765837Sbostic position &position::operator/=(double a)
17865837Sbostic {
17965837Sbostic x /= a;
18065837Sbostic y /= a;
18165837Sbostic return *this;
18265837Sbostic }
18365837Sbostic
operator -(const position & a)18465837Sbostic position operator-(const position &a)
18565837Sbostic {
18665837Sbostic return position(-a.x, -a.y);
18765837Sbostic }
18865837Sbostic
operator +(const position & a,const position & b)18965837Sbostic position operator+(const position &a, const position &b)
19065837Sbostic {
19165837Sbostic return position(a.x + b.x, a.y + b.y);
19265837Sbostic }
19365837Sbostic
operator -(const position & a,const position & b)19465837Sbostic position operator-(const position &a, const position &b)
19565837Sbostic {
19665837Sbostic return position(a.x - b.x, a.y - b.y);
19765837Sbostic }
19865837Sbostic
operator /(const position & a,double n)19965837Sbostic position operator/(const position &a, double n)
20065837Sbostic {
20165837Sbostic return position(a.x/n, a.y/n);
20265837Sbostic }
20365837Sbostic
operator *(const position & a,double n)20465837Sbostic position operator*(const position &a, double n)
20565837Sbostic {
20665837Sbostic return position(a.x*n, a.y*n);
20765837Sbostic }
20865837Sbostic
20965837Sbostic // dot product
21065837Sbostic
operator *(const position & a,const position & b)21165837Sbostic double operator*(const position &a, const position &b)
21265837Sbostic {
21365837Sbostic return a.x*b.x + a.y*b.y;
21465837Sbostic }
21565837Sbostic
hypot(const position & a)21665837Sbostic double hypot(const position &a)
21765837Sbostic {
21865837Sbostic return hypot(a.x, a.y);
21965837Sbostic }
22065837Sbostic
22165837Sbostic struct arrow_head_type {
22265837Sbostic double height;
22365837Sbostic double width;
22465837Sbostic int solid;
22565837Sbostic };
22665837Sbostic
draw_arrow(const position & pos,const distance & dir,const arrow_head_type & aht,const line_type & lt)22765837Sbostic void draw_arrow(const position &pos, const distance &dir,
22865837Sbostic const arrow_head_type &aht, const line_type <)
22965837Sbostic {
23065837Sbostic double hyp = hypot(dir);
23165837Sbostic if (hyp == 0.0) {
23265837Sbostic error("cannot draw arrow on object with zero length");
23365837Sbostic return;
23465837Sbostic }
23565837Sbostic position base = -dir;
23665837Sbostic base *= aht.height/hyp;
23765837Sbostic position n(dir.y, -dir.x);
23865837Sbostic n *= aht.width/(hyp*2.0);
23965837Sbostic line_type slt = lt;
24065837Sbostic slt.type = line_type::solid;
24165837Sbostic if (aht.solid && out->supports_filled_polygons()) {
24265837Sbostic position v[3];
24365837Sbostic v[0] = pos;
24465837Sbostic v[1] = pos + base + n;
24565837Sbostic v[2] = pos + base - n;
24665837Sbostic // A value > 1 means fill with the current color.
24765837Sbostic out->polygon(v, 3, slt, 2.0);
24865837Sbostic }
24965837Sbostic else {
25065837Sbostic position v[2];
25165837Sbostic v[0] = pos;
25265837Sbostic v[1] = pos + base + n;
25365837Sbostic out->line(pos + base - n, v, 2, slt);
25465837Sbostic }
25565837Sbostic }
25665837Sbostic
object()25765837Sbostic object::object() : prev(0), next(0)
25865837Sbostic {
25965837Sbostic }
26065837Sbostic
~object()26165837Sbostic object::~object()
26265837Sbostic {
26365837Sbostic }
26465837Sbostic
move_by(const position &)26565837Sbostic void object::move_by(const position &)
26665837Sbostic {
26765837Sbostic }
26865837Sbostic
print()26965837Sbostic void object::print()
27065837Sbostic {
27165837Sbostic }
27265837Sbostic
print_text()27365837Sbostic void object::print_text()
27465837Sbostic {
27565837Sbostic }
27665837Sbostic
blank()27765837Sbostic int object::blank()
27865837Sbostic {
27965837Sbostic return 0;
28065837Sbostic }
28165837Sbostic
28265837Sbostic struct bounding_box {
28365837Sbostic int blank;
28465837Sbostic position ll;
28565837Sbostic position ur;
28665837Sbostic
28765837Sbostic bounding_box();
28865837Sbostic void encompass(const position &);
28965837Sbostic };
29065837Sbostic
bounding_box()29165837Sbostic bounding_box::bounding_box()
29265837Sbostic : blank(1)
29365837Sbostic {
29465837Sbostic }
29565837Sbostic
encompass(const position & pos)29665837Sbostic void bounding_box::encompass(const position &pos)
29765837Sbostic {
29865837Sbostic if (blank) {
29965837Sbostic ll = pos;
30065837Sbostic ur = pos;
30165837Sbostic blank = 0;
30265837Sbostic }
30365837Sbostic else {
30465837Sbostic if (pos.x < ll.x)
30565837Sbostic ll.x = pos.x;
30665837Sbostic if (pos.y < ll.y)
30765837Sbostic ll.y = pos.y;
30865837Sbostic if (pos.x > ur.x)
30965837Sbostic ur.x = pos.x;
31065837Sbostic if (pos.y > ur.y)
31165837Sbostic ur.y = pos.y;
31265837Sbostic }
31365837Sbostic }
31465837Sbostic
update_bounding_box(bounding_box *)31565837Sbostic void object::update_bounding_box(bounding_box *)
31665837Sbostic {
31765837Sbostic }
31865837Sbostic
origin()31965837Sbostic position object::origin()
32065837Sbostic {
32165837Sbostic return position(0.0,0.0);
32265837Sbostic }
32365837Sbostic
north()32465837Sbostic position object::north()
32565837Sbostic {
32665837Sbostic return origin();
32765837Sbostic }
32865837Sbostic
south()32965837Sbostic position object::south()
33065837Sbostic {
33165837Sbostic return origin();
33265837Sbostic }
33365837Sbostic
east()33465837Sbostic position object::east()
33565837Sbostic {
33665837Sbostic return origin();
33765837Sbostic }
33865837Sbostic
west()33965837Sbostic position object::west()
34065837Sbostic {
34165837Sbostic return origin();
34265837Sbostic }
34365837Sbostic
north_east()34465837Sbostic position object::north_east()
34565837Sbostic {
34665837Sbostic return origin();
34765837Sbostic }
34865837Sbostic
north_west()34965837Sbostic position object::north_west()
35065837Sbostic {
35165837Sbostic return origin();
35265837Sbostic }
35365837Sbostic
south_east()35465837Sbostic position object::south_east()
35565837Sbostic {
35665837Sbostic return origin();
35765837Sbostic }
35865837Sbostic
south_west()35965837Sbostic position object::south_west()
36065837Sbostic {
36165837Sbostic return origin();
36265837Sbostic }
36365837Sbostic
start()36465837Sbostic position object::start()
36565837Sbostic {
36665837Sbostic return origin();
36765837Sbostic }
36865837Sbostic
end()36965837Sbostic position object::end()
37065837Sbostic {
37165837Sbostic return origin();
37265837Sbostic }
37365837Sbostic
center()37465837Sbostic position object::center()
37565837Sbostic {
37665837Sbostic return origin();
37765837Sbostic }
37865837Sbostic
width()37965837Sbostic double object::width()
38065837Sbostic {
38165837Sbostic return 0.0;
38265837Sbostic }
38365837Sbostic
radius()38465837Sbostic double object::radius()
38565837Sbostic {
38665837Sbostic return 0.0;
38765837Sbostic }
38865837Sbostic
height()38965837Sbostic double object::height()
39065837Sbostic {
39165837Sbostic return 0.0;
39265837Sbostic }
39365837Sbostic
find_label(const char *)39465837Sbostic place *object::find_label(const char *)
39565837Sbostic {
39665837Sbostic return 0;
39765837Sbostic }
39865837Sbostic
segment(const position & a,int n,segment * p)39965837Sbostic segment::segment(const position &a, int n, segment *p)
40065837Sbostic : pos(a), is_absolute(n), next(p)
40165837Sbostic {
40265837Sbostic }
40365837Sbostic
text_item(char * t,const char * fn,int ln)40465837Sbostic text_item::text_item(char *t, const char *fn, int ln)
40565837Sbostic : filename(fn), lineno(ln), text(t), next(0)
40665837Sbostic {
40765837Sbostic adj.h = CENTER_ADJUST;
40865837Sbostic adj.v = NONE_ADJUST;
40965837Sbostic }
41065837Sbostic
~text_item()41165837Sbostic text_item::~text_item()
41265837Sbostic {
41365837Sbostic a_delete text;
41465837Sbostic }
41565837Sbostic
object_spec(object_type t)41665837Sbostic object_spec::object_spec(object_type t) : type(t)
41765837Sbostic {
41865837Sbostic flags = 0;
41965837Sbostic tbl = 0;
42065837Sbostic segment_list = 0;
42165837Sbostic segment_width = segment_height = 0.0;
42265837Sbostic segment_is_absolute = 0;
42365837Sbostic text = 0;
42465837Sbostic with = 0;
42565837Sbostic dir = RIGHT_DIRECTION;
42665837Sbostic }
42765837Sbostic
~object_spec()42865837Sbostic object_spec::~object_spec()
42965837Sbostic {
43065837Sbostic delete tbl;
43165837Sbostic while (segment_list != 0) {
43265837Sbostic segment *tem = segment_list;
43365837Sbostic segment_list = segment_list->next;
43465837Sbostic delete tem;
43565837Sbostic }
43665837Sbostic object *p = oblist.head;
43765837Sbostic while (p != 0) {
43865837Sbostic object *tem = p;
43965837Sbostic p = p->next;
44065837Sbostic delete tem;
44165837Sbostic }
44265837Sbostic while (text != 0) {
44365837Sbostic text_item *tem = text;
44465837Sbostic text = text->next;
44565837Sbostic delete tem;
44665837Sbostic }
44765837Sbostic delete with;
44865837Sbostic }
44965837Sbostic
45065837Sbostic class command_object : public object {
45165837Sbostic char *s;
45265837Sbostic const char *filename;
45365837Sbostic int lineno;
45465837Sbostic public:
45565837Sbostic command_object(char *, const char *, int);
45665837Sbostic ~command_object();
type()45765837Sbostic object_type type() { return OTHER_OBJECT; }
45865837Sbostic void print();
45965837Sbostic };
46065837Sbostic
command_object(char * p,const char * fn,int ln)46165837Sbostic command_object::command_object(char *p, const char *fn, int ln)
46265837Sbostic : s(p), filename(fn), lineno(ln)
46365837Sbostic {
46465837Sbostic }
46565837Sbostic
~command_object()46665837Sbostic command_object::~command_object()
46765837Sbostic {
46865837Sbostic a_delete s;
46965837Sbostic }
47065837Sbostic
print()47165837Sbostic void command_object::print()
47265837Sbostic {
47365837Sbostic out->command(s, filename, lineno);
47465837Sbostic }
47565837Sbostic
make_command_object(char * s,const char * fn,int ln)47665837Sbostic object *make_command_object(char *s, const char *fn, int ln)
47765837Sbostic {
47865837Sbostic return new command_object(s, fn, ln);
47965837Sbostic }
48065837Sbostic
48165837Sbostic class mark_object : public object {
48265837Sbostic public:
48365837Sbostic mark_object();
48465837Sbostic object_type type();
48565837Sbostic };
48665837Sbostic
make_mark_object()48765837Sbostic object *make_mark_object()
48865837Sbostic {
48965837Sbostic return new mark_object();
49065837Sbostic }
49165837Sbostic
mark_object()49265837Sbostic mark_object::mark_object()
49365837Sbostic {
49465837Sbostic }
49565837Sbostic
type()49665837Sbostic object_type mark_object::type()
49765837Sbostic {
49865837Sbostic return MARK_OBJECT;
49965837Sbostic }
50065837Sbostic
object_list()50165837Sbostic object_list::object_list() : head(0), tail(0)
50265837Sbostic {
50365837Sbostic }
50465837Sbostic
append(object * obj)50565837Sbostic void object_list::append(object *obj)
50665837Sbostic {
50765837Sbostic if (tail == 0) {
50865837Sbostic obj->next = obj->prev = 0;
50965837Sbostic head = tail = obj;
51065837Sbostic }
51165837Sbostic else {
51265837Sbostic obj->prev = tail;
51365837Sbostic obj->next = 0;
51465837Sbostic tail->next = obj;
51565837Sbostic tail = obj;
51665837Sbostic }
51765837Sbostic }
51865837Sbostic
wrap_up_block(object_list * ol)51965837Sbostic void object_list::wrap_up_block(object_list *ol)
52065837Sbostic {
52165837Sbostic for (object *p = tail; p && p->type() != MARK_OBJECT; p = p->prev)
52265837Sbostic ;
52365837Sbostic assert(p != 0);
52465837Sbostic ol->head = p->next;
52565837Sbostic if (ol->head) {
52665837Sbostic ol->tail = tail;
52765837Sbostic ol->head->prev = 0;
52865837Sbostic }
52965837Sbostic else
53065837Sbostic ol->tail = 0;
53165837Sbostic tail = p->prev;
53265837Sbostic if (tail)
53365837Sbostic tail->next = 0;
53465837Sbostic else
53565837Sbostic head = 0;
53665837Sbostic delete p;
53765837Sbostic }
53865837Sbostic
text_piece()53965837Sbostic text_piece::text_piece()
54065837Sbostic : text(0), filename(0), lineno(-1)
54165837Sbostic {
54265837Sbostic adj.h = CENTER_ADJUST;
54365837Sbostic adj.v = NONE_ADJUST;
54465837Sbostic }
54565837Sbostic
~text_piece()54665837Sbostic text_piece::~text_piece()
54765837Sbostic {
54865837Sbostic a_delete text;
54965837Sbostic }
55065837Sbostic
55165837Sbostic class graphic_object : public object {
55265837Sbostic int ntext;
55365837Sbostic text_piece *text;
55465837Sbostic int aligned;
55565837Sbostic protected:
55665837Sbostic line_type lt;
55765837Sbostic public:
55865837Sbostic graphic_object();
55965837Sbostic ~graphic_object();
56065837Sbostic object_type type() = 0;
56165837Sbostic void print_text();
56265837Sbostic void add_text(text_item *, int);
56365837Sbostic void set_dotted(double);
56465837Sbostic void set_dashed(double);
56565837Sbostic void set_thickness(double);
56665837Sbostic void set_invisible();
56765837Sbostic virtual void set_fill(double);
56865837Sbostic };
56965837Sbostic
graphic_object()57065837Sbostic graphic_object::graphic_object() : ntext(0), text(0), aligned(0)
57165837Sbostic {
57265837Sbostic }
57365837Sbostic
set_dotted(double wid)57465837Sbostic void graphic_object::set_dotted(double wid)
57565837Sbostic {
57665837Sbostic lt.type = line_type::dotted;
57765837Sbostic lt.dash_width = wid;
57865837Sbostic }
57965837Sbostic
set_dashed(double wid)58065837Sbostic void graphic_object::set_dashed(double wid)
58165837Sbostic {
58265837Sbostic lt.type = line_type::dashed;
58365837Sbostic lt.dash_width = wid;
58465837Sbostic }
58565837Sbostic
set_thickness(double th)58665837Sbostic void graphic_object::set_thickness(double th)
58765837Sbostic {
58865837Sbostic lt.thickness = th;
58965837Sbostic }
59065837Sbostic
set_fill(double)59165837Sbostic void graphic_object::set_fill(double)
59265837Sbostic {
59365837Sbostic }
59465837Sbostic
set_invisible()59565837Sbostic void graphic_object::set_invisible()
59665837Sbostic {
59765837Sbostic lt.type = line_type::invisible;
59865837Sbostic }
59965837Sbostic
add_text(text_item * t,int a)60065837Sbostic void graphic_object::add_text(text_item *t, int a)
60165837Sbostic {
60265837Sbostic aligned = a;
60365837Sbostic int len = 0;
60465837Sbostic for (text_item *p = t; p; p = p->next)
60565837Sbostic len++;
60665837Sbostic if (len == 0)
60765837Sbostic text = 0;
60865837Sbostic else {
60965837Sbostic text = new text_piece[len];
61065837Sbostic for (p = t, len = 0; p; p = p->next, len++) {
61165837Sbostic text[len].text = p->text;
61265837Sbostic p->text = 0;
61365837Sbostic text[len].adj = p->adj;
61465837Sbostic text[len].filename = p->filename;
61565837Sbostic text[len].lineno = p->lineno;
61665837Sbostic }
61765837Sbostic }
61865837Sbostic ntext = len;
61965837Sbostic }
62065837Sbostic
print_text()62165837Sbostic void graphic_object::print_text()
62265837Sbostic {
62365837Sbostic double angle = 0.0;
62465837Sbostic if (aligned) {
62565837Sbostic position d(end() - start());
62665837Sbostic if (d.x != 0.0 || d.y != 0.0)
62765837Sbostic angle = atan2(d.y, d.x);
62865837Sbostic }
62965837Sbostic if (text != 0)
63065837Sbostic out->text(center(), text, ntext, angle);
63165837Sbostic }
63265837Sbostic
~graphic_object()63365837Sbostic graphic_object::~graphic_object()
63465837Sbostic {
63565837Sbostic if (text)
63665837Sbostic ad_delete(ntext) text;
63765837Sbostic }
63865837Sbostic
63965837Sbostic class rectangle_object : public graphic_object {
64065837Sbostic protected:
64165837Sbostic position cent;
64265837Sbostic position dim;
64365837Sbostic public:
64465837Sbostic rectangle_object(const position &);
width()64565837Sbostic double width() { return dim.x; }
height()64665837Sbostic double height() { return dim.y; }
origin()64765837Sbostic position origin() { return cent; }
center()64865837Sbostic position center() { return cent; }
north()64965837Sbostic position north() { return position(cent.x, cent.y + dim.y/2.0); }
south()65065837Sbostic position south() { return position(cent.x, cent.y - dim.y/2.0); }
east()65165837Sbostic position east() { return position(cent.x + dim.x/2.0, cent.y); }
west()65265837Sbostic position west() { return position(cent.x - dim.x/2.0, cent.y); }
north_east()65365837Sbostic position north_east() { return position(cent.x + dim.x/2.0, cent.y + dim.y/2.0); }
north_west()65465837Sbostic position north_west() { return position(cent.x - dim.x/2.0, cent.y + dim.y/2.0); }
south_east()65565837Sbostic position south_east() { return position(cent.x + dim.x/2.0, cent.y - dim.y/2.0); }
south_west()65665837Sbostic position south_west() { return position(cent.x - dim.x/2.0, cent.y - dim.y/2.0); }
65765837Sbostic object_type type() = 0;
65865837Sbostic void update_bounding_box(bounding_box *);
65965837Sbostic void move_by(const position &);
66065837Sbostic };
66165837Sbostic
rectangle_object(const position & d)66265837Sbostic rectangle_object::rectangle_object(const position &d)
66365837Sbostic : dim(d)
66465837Sbostic {
66565837Sbostic }
66665837Sbostic
update_bounding_box(bounding_box * p)66765837Sbostic void rectangle_object::update_bounding_box(bounding_box *p)
66865837Sbostic {
66965837Sbostic p->encompass(cent - dim/2.0);
67065837Sbostic p->encompass(cent + dim/2.0);
67165837Sbostic }
67265837Sbostic
move_by(const position & a)67365837Sbostic void rectangle_object::move_by(const position &a)
67465837Sbostic {
67565837Sbostic cent += a;
67665837Sbostic }
67765837Sbostic
67865837Sbostic class closed_object : public rectangle_object {
67965837Sbostic public:
68065837Sbostic closed_object(const position &);
68165837Sbostic object_type type() = 0;
68265837Sbostic void set_fill(double);
68365837Sbostic protected:
68465837Sbostic double fill; // < 0 if not filled
68565837Sbostic };
68665837Sbostic
closed_object(const position & pos)68765837Sbostic closed_object::closed_object(const position &pos)
68865837Sbostic : rectangle_object(pos), fill(-1.0)
68965837Sbostic {
69065837Sbostic }
69165837Sbostic
set_fill(double f)69265837Sbostic void closed_object::set_fill(double f)
69365837Sbostic {
69465837Sbostic assert(f >= 0.0);
69565837Sbostic fill = f;
69665837Sbostic }
69765837Sbostic
69865837Sbostic
69965837Sbostic class box_object : public closed_object {
70065837Sbostic double xrad;
70165837Sbostic double yrad;
70265837Sbostic public:
70365837Sbostic box_object(const position &, double);
type()70465837Sbostic object_type type() { return BOX_OBJECT; }
70565837Sbostic void print();
70665837Sbostic position north_east();
70765837Sbostic position north_west();
70865837Sbostic position south_east();
70965837Sbostic position south_west();
71065837Sbostic };
71165837Sbostic
box_object(const position & pos,double r)71265837Sbostic box_object::box_object(const position &pos, double r)
71365837Sbostic : closed_object(pos), xrad(dim.x > 0 ? r : -r), yrad(dim.y > 0 ? r : -r)
71465837Sbostic {
71565837Sbostic }
71665837Sbostic
71765837Sbostic const double CHOP_FACTOR = 1.0 - 1.0/M_SQRT2;
71865837Sbostic
north_east()71965837Sbostic position box_object::north_east()
72065837Sbostic {
72165837Sbostic return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad,
72265837Sbostic cent.y + dim.y/2.0 - CHOP_FACTOR*yrad);
72365837Sbostic }
72465837Sbostic
north_west()72565837Sbostic position box_object::north_west()
72665837Sbostic {
72765837Sbostic return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad,
72865837Sbostic cent.y + dim.y/2.0 - CHOP_FACTOR*yrad);
72965837Sbostic }
73065837Sbostic
south_east()73165837Sbostic position box_object::south_east()
73265837Sbostic {
73365837Sbostic return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad,
73465837Sbostic cent.y - dim.y/2.0 + CHOP_FACTOR*yrad);
73565837Sbostic }
73665837Sbostic
south_west()73765837Sbostic position box_object::south_west()
73865837Sbostic {
73965837Sbostic return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad,
74065837Sbostic cent.y - dim.y/2.0 + CHOP_FACTOR*yrad);
74165837Sbostic }
74265837Sbostic
print()74365837Sbostic void box_object::print()
74465837Sbostic {
74565837Sbostic if (lt.type == line_type::invisible && fill < 0.0)
74665837Sbostic return;
74765837Sbostic if (xrad == 0.0) {
74865837Sbostic distance dim2 = dim/2.0;
74965837Sbostic position vec[4];
75065837Sbostic vec[0] = cent + position(dim2.x, -dim2.y);
75165837Sbostic vec[1] = cent + position(dim2.x, dim2.y);
75265837Sbostic vec[2] = cent + position(-dim2.x, dim2.y);
75365837Sbostic vec[3] = cent + position(-dim2.x, -dim2.y);
75465837Sbostic out->polygon(vec, 4, lt, fill);
75565837Sbostic }
75665837Sbostic else {
75765837Sbostic distance abs_dim(fabs(dim.x), fabs(dim.y));
75865837Sbostic out->rounded_box(cent, abs_dim, fabs(xrad), lt, fill);
75965837Sbostic }
76065837Sbostic }
76165837Sbostic
make_box(position * curpos,direction * dirp)76265837Sbostic graphic_object *object_spec::make_box(position *curpos, direction *dirp)
76365837Sbostic {
76465837Sbostic static double last_box_height;
76565837Sbostic static double last_box_width;
76665837Sbostic static double last_box_radius;
76765837Sbostic static int have_last_box = 0;
76865837Sbostic if (!(flags & HAS_HEIGHT)) {
76965837Sbostic if ((flags & IS_SAME) && have_last_box)
77065837Sbostic height = last_box_height;
77165837Sbostic else
77265837Sbostic lookup_variable("boxht", &height);
77365837Sbostic }
77465837Sbostic if (!(flags & HAS_WIDTH)) {
77565837Sbostic if ((flags & IS_SAME) && have_last_box)
77665837Sbostic width = last_box_width;
77765837Sbostic else
77865837Sbostic lookup_variable("boxwid", &width);
77965837Sbostic }
78065837Sbostic if (!(flags & HAS_RADIUS)) {
78165837Sbostic if ((flags & IS_SAME) && have_last_box)
78265837Sbostic radius = last_box_radius;
78365837Sbostic else
78465837Sbostic lookup_variable("boxrad", &radius);
78565837Sbostic }
78665837Sbostic last_box_width = width;
78765837Sbostic last_box_height = height;
78865837Sbostic last_box_radius = radius;
78965837Sbostic have_last_box = 1;
79065837Sbostic radius = fabs(radius);
79165837Sbostic if (radius*2.0 > fabs(width))
79265837Sbostic radius = fabs(width/2.0);
79365837Sbostic if (radius*2.0 > fabs(height))
79465837Sbostic radius = fabs(height/2.0);
79565837Sbostic box_object *p = new box_object(position(width, height), radius);
79665837Sbostic if (!position_rectangle(p, curpos, dirp)) {
79765837Sbostic delete p;
79865837Sbostic p = 0;
79965837Sbostic }
80065837Sbostic return p;
80165837Sbostic }
80265837Sbostic
80365837Sbostic // return non-zero for success
80465837Sbostic
position_rectangle(rectangle_object * p,position * curpos,direction * dirp)80565837Sbostic int object_spec::position_rectangle(rectangle_object *p,
80665837Sbostic position *curpos, direction *dirp)
80765837Sbostic {
80865837Sbostic position pos;
80965837Sbostic dir = *dirp; // ignore any direction in attribute list
81065837Sbostic position motion;
81165837Sbostic switch (dir) {
81265837Sbostic case UP_DIRECTION:
81365837Sbostic motion.y = p->height()/2.0;
81465837Sbostic break;
81565837Sbostic case DOWN_DIRECTION:
81665837Sbostic motion.y = -p->height()/2.0;
81765837Sbostic break;
81865837Sbostic case LEFT_DIRECTION:
81965837Sbostic motion.x = -p->width()/2.0;
82065837Sbostic break;
82165837Sbostic case RIGHT_DIRECTION:
82265837Sbostic motion.x = p->width()/2.0;
82365837Sbostic break;
82465837Sbostic default:
82565837Sbostic assert(0);
82665837Sbostic }
82765837Sbostic if (flags & HAS_AT) {
82865837Sbostic pos = at;
82965837Sbostic if (flags & HAS_WITH) {
83065837Sbostic place offset;
83165837Sbostic place here;
83265837Sbostic here.obj = p;
83365837Sbostic if (!with->follow(here, &offset))
83465837Sbostic return 0;
83565837Sbostic pos -= offset;
83665837Sbostic }
83765837Sbostic }
83865837Sbostic else {
83965837Sbostic pos = *curpos;
84065837Sbostic pos += motion;
84165837Sbostic }
84265837Sbostic p->move_by(pos);
84365837Sbostic pos += motion;
84465837Sbostic *curpos = pos;
84565837Sbostic return 1;
84665837Sbostic }
84765837Sbostic
84865837Sbostic class block_object : public rectangle_object {
84965837Sbostic object_list oblist;
85065837Sbostic PTABLE(place) *tbl;
85165837Sbostic public:
85265837Sbostic block_object(const position &, const object_list &ol, PTABLE(place) *t);
85365837Sbostic ~block_object();
85465837Sbostic place *find_label(const char *);
85565837Sbostic object_type type();
85665837Sbostic void move_by(const position &);
85765837Sbostic void print();
85865837Sbostic };
85965837Sbostic
block_object(const position & d,const object_list & ol,PTABLE (place)* t)86065837Sbostic block_object::block_object(const position &d, const object_list &ol,
86165837Sbostic PTABLE(place) *t)
86265837Sbostic : oblist(ol), tbl(t), rectangle_object(d)
86365837Sbostic {
86465837Sbostic }
86565837Sbostic
~block_object()86665837Sbostic block_object::~block_object()
86765837Sbostic {
86865837Sbostic delete tbl;
86965837Sbostic object *p = oblist.head;
87065837Sbostic while (p != 0) {
87165837Sbostic object *tem = p;
87265837Sbostic p = p->next;
87365837Sbostic delete tem;
87465837Sbostic }
87565837Sbostic }
87665837Sbostic
print()87765837Sbostic void block_object::print()
87865837Sbostic {
87965837Sbostic out->begin_block(south_west(), north_east());
88065837Sbostic print_object_list(oblist.head);
88165837Sbostic out->end_block();
88265837Sbostic }
88365837Sbostic
adjust_objectless_places(PTABLE (place)* tbl,const position & a)88465837Sbostic static void adjust_objectless_places(PTABLE(place) *tbl, const position &a)
88565837Sbostic {
88665837Sbostic // Adjust all the labels that aren't attached to objects.
88765837Sbostic PTABLE_ITERATOR(place) iter(tbl);
88865837Sbostic const char *key;
88965837Sbostic place *pl;
89065837Sbostic while (iter.next(&key, &pl))
89165837Sbostic if (key && csupper(key[0]) && pl->obj == 0) {
89265837Sbostic pl->x += a.x;
89365837Sbostic pl->y += a.y;
89465837Sbostic }
89565837Sbostic }
89665837Sbostic
move_by(const position & a)89765837Sbostic void block_object::move_by(const position &a)
89865837Sbostic {
89965837Sbostic cent += a;
90065837Sbostic for (object *p = oblist.head; p; p = p->next)
90165837Sbostic p->move_by(a);
90265837Sbostic adjust_objectless_places(tbl, a);
90365837Sbostic }
90465837Sbostic
90565837Sbostic
find_label(const char * name)90665837Sbostic place *block_object::find_label(const char *name)
90765837Sbostic {
90865837Sbostic return tbl->lookup(name);
90965837Sbostic }
91065837Sbostic
type()91165837Sbostic object_type block_object::type()
91265837Sbostic {
91365837Sbostic return BLOCK_OBJECT;
91465837Sbostic }
91565837Sbostic
make_block(position * curpos,direction * dirp)91665837Sbostic graphic_object *object_spec::make_block(position *curpos, direction *dirp)
91765837Sbostic {
91865837Sbostic bounding_box bb;
91965837Sbostic for (object *p = oblist.head; p; p = p->next)
92065837Sbostic p->update_bounding_box(&bb);
92165837Sbostic position dim;
92265837Sbostic if (!bb.blank) {
92365837Sbostic position m = -(bb.ll + bb.ur)/2.0;
92465837Sbostic for (object *p = oblist.head; p; p = p->next)
92565837Sbostic p->move_by(m);
92665837Sbostic adjust_objectless_places(tbl, m);
92765837Sbostic dim = bb.ur - bb.ll;
92865837Sbostic }
92965837Sbostic if (flags & HAS_WIDTH)
93065837Sbostic dim.x = width;
93165837Sbostic if (flags & HAS_HEIGHT)
93265837Sbostic dim.y = height;
93365837Sbostic block_object *block = new block_object(dim, oblist, tbl);
93465837Sbostic if (!position_rectangle(block, curpos, dirp)) {
93565837Sbostic delete block;
93665837Sbostic block = 0;
93765837Sbostic }
93865837Sbostic tbl = 0;
93965837Sbostic oblist.head = oblist.tail = 0;
94065837Sbostic return block;
94165837Sbostic }
94265837Sbostic
94365837Sbostic class text_object : public rectangle_object {
94465837Sbostic public:
94565837Sbostic text_object(const position &);
type()94665837Sbostic object_type type() { return TEXT_OBJECT; }
94765837Sbostic };
94865837Sbostic
text_object(const position & d)94965837Sbostic text_object::text_object(const position &d)
95065837Sbostic : rectangle_object(d)
95165837Sbostic {
95265837Sbostic }
95365837Sbostic
make_text(position * curpos,direction * dirp)95465837Sbostic graphic_object *object_spec::make_text(position *curpos, direction *dirp)
95565837Sbostic {
95665837Sbostic if (!(flags & HAS_HEIGHT)) {
95765837Sbostic lookup_variable("textht", &height);
95865837Sbostic int nitems = 0;
95965837Sbostic for (text_item *t = text; t; t = t->next)
96065837Sbostic nitems++;
96165837Sbostic height *= nitems;
96265837Sbostic }
96365837Sbostic if (!(flags & HAS_WIDTH))
96465837Sbostic lookup_variable("textwid", &width);
96565837Sbostic text_object *p = new text_object(position(width, height));
96665837Sbostic if (!position_rectangle(p, curpos, dirp)) {
96765837Sbostic delete p;
96865837Sbostic p = 0;
96965837Sbostic }
97065837Sbostic return p;
97165837Sbostic }
97265837Sbostic
97365837Sbostic
97465837Sbostic class ellipse_object : public closed_object {
97565837Sbostic public:
97665837Sbostic ellipse_object(const position &);
north_east()97765837Sbostic position north_east() { return position(cent.x + dim.x/(M_SQRT2*2.0),
97865837Sbostic cent.y + dim.y/(M_SQRT2*2.0)); }
north_west()97965837Sbostic position north_west() { return position(cent.x - dim.x/(M_SQRT2*2.0),
98065837Sbostic cent.y + dim.y/(M_SQRT2*2.0)); }
south_east()98165837Sbostic position south_east() { return position(cent.x + dim.x/(M_SQRT2*2.0),
98265837Sbostic cent.y - dim.y/(M_SQRT2*2.0)); }
south_west()98365837Sbostic position south_west() { return position(cent.x - dim.x/(M_SQRT2*2.0),
98465837Sbostic cent.y - dim.y/(M_SQRT2*2.0)); }
radius()98565837Sbostic double radius() { return dim.x/2.0; }
type()98665837Sbostic object_type type() { return ELLIPSE_OBJECT; }
98765837Sbostic void print();
98865837Sbostic };
98965837Sbostic
ellipse_object(const position & d)99065837Sbostic ellipse_object::ellipse_object(const position &d)
99165837Sbostic : closed_object(d)
99265837Sbostic {
99365837Sbostic }
99465837Sbostic
print()99565837Sbostic void ellipse_object::print()
99665837Sbostic {
99765837Sbostic if (lt.type == line_type::invisible && fill < 0.0)
99865837Sbostic return;
99965837Sbostic out->ellipse(cent, dim, lt, fill);
100065837Sbostic }
100165837Sbostic
make_ellipse(position * curpos,direction * dirp)100265837Sbostic graphic_object *object_spec::make_ellipse(position *curpos, direction *dirp)
100365837Sbostic {
100465837Sbostic static double last_ellipse_height;
100565837Sbostic static double last_ellipse_width;
100665837Sbostic static int have_last_ellipse = 0;
100765837Sbostic if (!(flags & HAS_HEIGHT)) {
100865837Sbostic if ((flags & IS_SAME) && have_last_ellipse)
100965837Sbostic height = last_ellipse_height;
101065837Sbostic else
101165837Sbostic lookup_variable("ellipseht", &height);
101265837Sbostic }
101365837Sbostic if (!(flags & HAS_WIDTH)) {
101465837Sbostic if ((flags & IS_SAME) && have_last_ellipse)
101565837Sbostic width = last_ellipse_width;
101665837Sbostic else
101765837Sbostic lookup_variable("ellipsewid", &width);
101865837Sbostic }
101965837Sbostic last_ellipse_width = width;
102065837Sbostic last_ellipse_height = height;
102165837Sbostic have_last_ellipse = 1;
102265837Sbostic ellipse_object *p = new ellipse_object(position(width, height));
102365837Sbostic if (!position_rectangle(p, curpos, dirp)) {
102465837Sbostic delete p;
102565837Sbostic return 0;
102665837Sbostic }
102765837Sbostic return p;
102865837Sbostic }
102965837Sbostic
103065837Sbostic class circle_object : public ellipse_object {
103165837Sbostic public:
103265837Sbostic circle_object(double);
type()103365837Sbostic object_type type() { return CIRCLE_OBJECT; }
103465837Sbostic void print();
103565837Sbostic };
103665837Sbostic
1037*65838Sbostic /*
1038*65838Sbostic * XXX call posref to gain reference to avoid g++ core dump.
1039*65838Sbostic * From: Chris Torek <torek@BSDI.COM>
1040*65838Sbostic */
circle_object(double diam)104165837Sbostic circle_object::circle_object(double diam)
1042*65838Sbostic : ellipse_object(posref(position(diam, diam)))
104365837Sbostic {
104465837Sbostic }
104565837Sbostic
print()104665837Sbostic void circle_object::print()
104765837Sbostic {
104865837Sbostic if (lt.type == line_type::invisible && fill < 0.0)
104965837Sbostic return;
105065837Sbostic out->circle(cent, dim.x/2.0, lt, fill);
105165837Sbostic }
105265837Sbostic
make_circle(position * curpos,direction * dirp)105365837Sbostic graphic_object *object_spec::make_circle(position *curpos, direction *dirp)
105465837Sbostic {
105565837Sbostic static double last_circle_radius;
105665837Sbostic static int have_last_circle = 0;
105765837Sbostic if (!(flags & HAS_RADIUS)) {
105865837Sbostic if ((flags & IS_SAME) && have_last_circle)
105965837Sbostic radius = last_circle_radius;
106065837Sbostic else
106165837Sbostic lookup_variable("circlerad", &radius);
106265837Sbostic }
106365837Sbostic last_circle_radius = radius;
106465837Sbostic have_last_circle = 1;
106565837Sbostic circle_object *p = new circle_object(radius*2.0);
106665837Sbostic if (!position_rectangle(p, curpos, dirp)) {
106765837Sbostic delete p;
106865837Sbostic return 0;
106965837Sbostic }
107065837Sbostic return p;
107165837Sbostic }
107265837Sbostic
107365837Sbostic class move_object : public graphic_object {
107465837Sbostic position strt;
107565837Sbostic position en;
107665837Sbostic public:
107765837Sbostic move_object(const position &s, const position &e);
origin()107865837Sbostic position origin() { return en; }
type()107965837Sbostic object_type type() { return MOVE_OBJECT; }
108065837Sbostic void update_bounding_box(bounding_box *);
108165837Sbostic void move_by(const position &);
108265837Sbostic };
108365837Sbostic
move_object(const position & s,const position & e)108465837Sbostic move_object::move_object(const position &s, const position &e)
108565837Sbostic : strt(s), en(e)
108665837Sbostic {
108765837Sbostic }
108865837Sbostic
update_bounding_box(bounding_box * p)108965837Sbostic void move_object::update_bounding_box(bounding_box *p)
109065837Sbostic {
109165837Sbostic p->encompass(strt);
109265837Sbostic p->encompass(en);
109365837Sbostic }
109465837Sbostic
move_by(const position & a)109565837Sbostic void move_object::move_by(const position &a)
109665837Sbostic {
109765837Sbostic strt += a;
109865837Sbostic en += a;
109965837Sbostic }
110065837Sbostic
make_move(position * curpos,direction * dirp)110165837Sbostic graphic_object *object_spec::make_move(position *curpos, direction *dirp)
110265837Sbostic {
110365837Sbostic static position last_move;
110465837Sbostic static int have_last_move = 0;
110565837Sbostic *dirp = dir;
110665837Sbostic // No need to look at at since `at' attribute sets `from' attribute.
110765837Sbostic position startpos = (flags & HAS_FROM) ? from : *curpos;
110865837Sbostic if (!(flags & HAS_SEGMENT)) {
110965837Sbostic if ((flags && IS_SAME) && have_last_move)
111065837Sbostic segment_pos = last_move;
111165837Sbostic else {
111265837Sbostic switch (dir) {
111365837Sbostic case UP_DIRECTION:
111465837Sbostic segment_pos.y = segment_height;
111565837Sbostic break;
111665837Sbostic case DOWN_DIRECTION:
111765837Sbostic segment_pos.y = -segment_height;
111865837Sbostic break;
111965837Sbostic case LEFT_DIRECTION:
112065837Sbostic segment_pos.x = -segment_width;
112165837Sbostic break;
112265837Sbostic case RIGHT_DIRECTION:
112365837Sbostic segment_pos.x = segment_width;
112465837Sbostic break;
112565837Sbostic default:
112665837Sbostic assert(0);
112765837Sbostic }
112865837Sbostic }
112965837Sbostic }
113065837Sbostic segment_list = new segment(segment_pos, segment_is_absolute, segment_list);
113165837Sbostic // Reverse the segment_list so that it's in forward order.
113265837Sbostic segment *old = segment_list;
113365837Sbostic segment_list = 0;
113465837Sbostic while (old != 0) {
113565837Sbostic segment *tem = old->next;
113665837Sbostic old->next = segment_list;
113765837Sbostic segment_list = old;
113865837Sbostic old = tem;
113965837Sbostic }
114065837Sbostic // Compute the end position.
114165837Sbostic position endpos = startpos;
114265837Sbostic for (segment *s = segment_list; s; s = s->next)
114365837Sbostic if (s->is_absolute)
114465837Sbostic endpos = s->pos;
114565837Sbostic else
114665837Sbostic endpos += s->pos;
114765837Sbostic have_last_move = 1;
114865837Sbostic last_move = endpos - startpos;
114965837Sbostic move_object *p = new move_object(startpos, endpos);
115065837Sbostic *curpos = endpos;
115165837Sbostic return p;
115265837Sbostic }
115365837Sbostic
115465837Sbostic class linear_object : public graphic_object {
115565837Sbostic protected:
115665837Sbostic char arrow_at_start;
115765837Sbostic char arrow_at_end;
115865837Sbostic arrow_head_type aht;
115965837Sbostic position strt;
116065837Sbostic position en;
116165837Sbostic public:
116265837Sbostic linear_object(const position &s, const position &e);
start()116365837Sbostic position start() { return strt; }
end()116465837Sbostic position end() { return en; }
116565837Sbostic void move_by(const position &);
116665837Sbostic void update_bounding_box(bounding_box *) = 0;
116765837Sbostic object_type type() = 0;
116865837Sbostic void add_arrows(int at_start, int at_end, const arrow_head_type &);
116965837Sbostic };
117065837Sbostic
117165837Sbostic class line_object : public linear_object {
117265837Sbostic protected:
117365837Sbostic position *v;
117465837Sbostic int n;
117565837Sbostic public:
117665837Sbostic line_object(const position &s, const position &e, position *, int);
117765837Sbostic ~line_object();
origin()117865837Sbostic position origin() { return strt; }
center()117965837Sbostic position center() { return (strt + en)/2.0; }
north()118065837Sbostic position north() { return (en.y - strt.y) > 0 ? en : strt; }
south()118165837Sbostic position south() { return (en.y - strt.y) < 0 ? en : strt; }
east()118265837Sbostic position east() { return (en.x - strt.x) > 0 ? en : strt; }
west()118365837Sbostic position west() { return (en.x - strt.x) < 0 ? en : strt; }
type()118465837Sbostic object_type type() { return LINE_OBJECT; }
118565837Sbostic void update_bounding_box(bounding_box *);
118665837Sbostic void print();
118765837Sbostic void move_by(const position &);
118865837Sbostic };
118965837Sbostic
119065837Sbostic class arrow_object : public line_object {
119165837Sbostic public:
119265837Sbostic arrow_object(const position &, const position &, position *, int);
type()119365837Sbostic object_type type() { return ARROW_OBJECT; }
119465837Sbostic };
119565837Sbostic
119665837Sbostic class spline_object : public line_object {
119765837Sbostic public:
119865837Sbostic spline_object(const position &, const position &, position *, int);
type()119965837Sbostic object_type type() { return SPLINE_OBJECT; }
120065837Sbostic void print();
120165837Sbostic void update_bounding_box(bounding_box *);
120265837Sbostic };
120365837Sbostic
linear_object(const position & s,const position & e)120465837Sbostic linear_object::linear_object(const position &s, const position &e)
120565837Sbostic : strt(s), en(e), arrow_at_start(0), arrow_at_end(0)
120665837Sbostic {
120765837Sbostic }
120865837Sbostic
move_by(const position & a)120965837Sbostic void linear_object::move_by(const position &a)
121065837Sbostic {
121165837Sbostic strt += a;
121265837Sbostic en += a;
121365837Sbostic }
121465837Sbostic
add_arrows(int at_start,int at_end,const arrow_head_type & a)121565837Sbostic void linear_object::add_arrows(int at_start, int at_end,
121665837Sbostic const arrow_head_type &a)
121765837Sbostic {
121865837Sbostic arrow_at_start = at_start;
121965837Sbostic arrow_at_end = at_end;
122065837Sbostic aht = a;
122165837Sbostic }
122265837Sbostic
line_object(const position & s,const position & e,position * p,int i)122365837Sbostic line_object::line_object(const position &s, const position &e,
122465837Sbostic position *p, int i)
122565837Sbostic : v(p), n(i), linear_object(s, e)
122665837Sbostic {
122765837Sbostic }
122865837Sbostic
print()122965837Sbostic void line_object::print()
123065837Sbostic {
123165837Sbostic if (lt.type == line_type::invisible)
123265837Sbostic return;
123365837Sbostic out->line(strt, v, n, lt);
123465837Sbostic if (arrow_at_start)
123565837Sbostic draw_arrow(strt, strt-v[0], aht, lt);
123665837Sbostic if (arrow_at_end)
123765837Sbostic draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);
123865837Sbostic }
123965837Sbostic
update_bounding_box(bounding_box * p)124065837Sbostic void line_object::update_bounding_box(bounding_box *p)
124165837Sbostic {
124265837Sbostic p->encompass(strt);
124365837Sbostic for (int i = 0; i < n; i++)
124465837Sbostic p->encompass(v[i]);
124565837Sbostic }
124665837Sbostic
move_by(const position & pos)124765837Sbostic void line_object::move_by(const position &pos)
124865837Sbostic {
124965837Sbostic linear_object::move_by(pos);
125065837Sbostic for (int i = 0; i < n; i++)
125165837Sbostic v[i] += pos;
125265837Sbostic }
125365837Sbostic
update_bounding_box(bounding_box * p)125465837Sbostic void spline_object::update_bounding_box(bounding_box *p)
125565837Sbostic {
125665837Sbostic p->encompass(strt);
125765837Sbostic p->encompass(en);
125865837Sbostic /*
125965837Sbostic
126065837Sbostic If
126165837Sbostic
126265837Sbostic p1 = q1/2 + q2/2
126365837Sbostic p2 = q1/6 + q2*5/6
126465837Sbostic p3 = q2*5/6 + q3/6
126565837Sbostic p4 = q2/2 + q3/2
126665837Sbostic [ the points for the Bezier cubic ]
126765837Sbostic
126865837Sbostic and
126965837Sbostic
127065837Sbostic t = .5
127165837Sbostic
127265837Sbostic then
127365837Sbostic
127465837Sbostic (1-t)^3*p1 + 3*t*(t - 1)^2*p2 + 3*t^2*(1-t)*p3 + t^3*p4
127565837Sbostic [ the equation for the Bezier cubic ]
127665837Sbostic
127765837Sbostic = .125*q1 + .75*q2 + .125*q3
127865837Sbostic
127965837Sbostic */
128065837Sbostic for (int i = 1; i < n; i++)
128165837Sbostic p->encompass((i == 1 ? strt : v[i-2])*.125 + v[i-1]*.75 + v[i]*.125);
128265837Sbostic }
128365837Sbostic
arrow_object(const position & s,const position & e,position * p,int i)128465837Sbostic arrow_object::arrow_object(const position &s, const position &e,
128565837Sbostic position *p, int i)
128665837Sbostic : line_object(s, e, p, i)
128765837Sbostic {
128865837Sbostic }
128965837Sbostic
spline_object(const position & s,const position & e,position * p,int i)129065837Sbostic spline_object::spline_object(const position &s, const position &e,
129165837Sbostic position *p, int i)
129265837Sbostic : line_object(s, e, p, i)
129365837Sbostic {
129465837Sbostic }
129565837Sbostic
print()129665837Sbostic void spline_object::print()
129765837Sbostic {
129865837Sbostic if (lt.type == line_type::invisible)
129965837Sbostic return;
130065837Sbostic out->spline(strt, v, n, lt);
130165837Sbostic if (arrow_at_start)
130265837Sbostic draw_arrow(strt, strt-v[0], aht, lt);
130365837Sbostic if (arrow_at_end)
130465837Sbostic draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);
130565837Sbostic }
130665837Sbostic
~line_object()130765837Sbostic line_object::~line_object()
130865837Sbostic {
130965837Sbostic a_delete v;
131065837Sbostic }
131165837Sbostic
make_line(position * curpos,direction * dirp)131265837Sbostic linear_object *object_spec::make_line(position *curpos, direction *dirp)
131365837Sbostic {
131465837Sbostic static position last_line;
131565837Sbostic static int have_last_line = 0;
131665837Sbostic *dirp = dir;
131765837Sbostic // No need to look at at since `at' attribute sets `from' attribute.
131865837Sbostic position startpos = (flags & HAS_FROM) ? from : *curpos;
131965837Sbostic if (!(flags & HAS_SEGMENT)) {
132065837Sbostic if ((flags & IS_SAME) && (type == LINE_OBJECT || type == ARROW_OBJECT)
132165837Sbostic && have_last_line)
132265837Sbostic segment_pos = last_line;
132365837Sbostic else
132465837Sbostic switch (dir) {
132565837Sbostic case UP_DIRECTION:
132665837Sbostic segment_pos.y = segment_height;
132765837Sbostic break;
132865837Sbostic case DOWN_DIRECTION:
132965837Sbostic segment_pos.y = -segment_height;
133065837Sbostic break;
133165837Sbostic case LEFT_DIRECTION:
133265837Sbostic segment_pos.x = -segment_width;
133365837Sbostic break;
133465837Sbostic case RIGHT_DIRECTION:
133565837Sbostic segment_pos.x = segment_width;
133665837Sbostic break;
133765837Sbostic default:
133865837Sbostic assert(0);
133965837Sbostic }
134065837Sbostic }
134165837Sbostic segment_list = new segment(segment_pos, segment_is_absolute, segment_list);
134265837Sbostic // reverse the segment_list so that it's in forward order
134365837Sbostic segment *old = segment_list;
134465837Sbostic segment_list = 0;
134565837Sbostic while (old != 0) {
134665837Sbostic segment *tem = old->next;
134765837Sbostic old->next = segment_list;
134865837Sbostic segment_list = old;
134965837Sbostic old = tem;
135065837Sbostic }
135165837Sbostic // Absolutise all movements
135265837Sbostic position endpos = startpos;
135365837Sbostic int nsegments = 0;
135465837Sbostic for (segment *s = segment_list; s; s = s->next, nsegments++)
135565837Sbostic if (s->is_absolute)
135665837Sbostic endpos = s->pos;
135765837Sbostic else {
135865837Sbostic endpos += s->pos;
135965837Sbostic s->pos = endpos;
136065837Sbostic s->is_absolute = 1; // to avoid confusion
136165837Sbostic }
136265837Sbostic // handle chop
136365837Sbostic line_object *p = 0;
136465837Sbostic position *v = new position[nsegments];
136565837Sbostic int i = 0;
136665837Sbostic for (s = segment_list; s; s = s->next, i++)
136765837Sbostic v[i] = s->pos;
136865837Sbostic if (flags & IS_DEFAULT_CHOPPED) {
136965837Sbostic lookup_variable("circlerad", &start_chop);
137065837Sbostic end_chop = start_chop;
137165837Sbostic flags |= IS_CHOPPED;
137265837Sbostic }
137365837Sbostic if (flags & IS_CHOPPED) {
137465837Sbostic position start_chop_vec, end_chop_vec;
137565837Sbostic if (start_chop != 0.0) {
137665837Sbostic start_chop_vec = v[0] - startpos;
137765837Sbostic start_chop_vec *= start_chop / hypot(start_chop_vec);
137865837Sbostic }
137965837Sbostic if (end_chop != 0.0) {
138065837Sbostic end_chop_vec = (v[nsegments - 1]
138165837Sbostic - (nsegments > 1 ? v[nsegments - 2] : startpos));
138265837Sbostic end_chop_vec *= end_chop / hypot(end_chop_vec);
138365837Sbostic }
138465837Sbostic startpos += start_chop_vec;
138565837Sbostic v[nsegments - 1] -= end_chop_vec;
138665837Sbostic endpos -= end_chop_vec;
138765837Sbostic }
138865837Sbostic switch (type) {
138965837Sbostic case SPLINE_OBJECT:
139065837Sbostic p = new spline_object(startpos, endpos, v, nsegments);
139165837Sbostic break;
139265837Sbostic case ARROW_OBJECT:
139365837Sbostic p = new arrow_object(startpos, endpos, v, nsegments);
139465837Sbostic break;
139565837Sbostic case LINE_OBJECT:
139665837Sbostic p = new line_object(startpos, endpos, v, nsegments);
139765837Sbostic break;
139865837Sbostic default:
139965837Sbostic assert(0);
140065837Sbostic }
140165837Sbostic have_last_line = 1;
140265837Sbostic last_line = endpos - startpos;
140365837Sbostic *curpos = endpos;
140465837Sbostic return p;
140565837Sbostic }
140665837Sbostic
140765837Sbostic class arc_object : public linear_object {
140865837Sbostic int clockwise;
140965837Sbostic position cent;
141065837Sbostic double rad;
141165837Sbostic public:
141265837Sbostic arc_object(int, const position &, const position &, const position &);
origin()141365837Sbostic position origin() { return cent; }
center()141465837Sbostic position center() { return cent; }
radius()141565837Sbostic double radius() { return rad; }
141665837Sbostic position north();
141765837Sbostic position south();
141865837Sbostic position east();
141965837Sbostic position west();
142065837Sbostic position north_east();
142165837Sbostic position north_west();
142265837Sbostic position south_east();
142365837Sbostic position south_west();
142465837Sbostic void update_bounding_box(bounding_box *);
type()142565837Sbostic object_type type() { return ARC_OBJECT; }
142665837Sbostic void print();
142765837Sbostic void move_by(const position &pos);
142865837Sbostic };
142965837Sbostic
arc_object(int cw,const position & s,const position & e,const position & c)143065837Sbostic arc_object::arc_object(int cw, const position &s, const position &e,
143165837Sbostic const position &c)
143265837Sbostic : linear_object(s, e), clockwise(cw), cent(c)
143365837Sbostic {
143465837Sbostic rad = hypot(c - s);
143565837Sbostic }
143665837Sbostic
move_by(const position & pos)143765837Sbostic void arc_object::move_by(const position &pos)
143865837Sbostic {
143965837Sbostic linear_object::move_by(pos);
144065837Sbostic cent += pos;
144165837Sbostic }
144265837Sbostic
144365837Sbostic // we get arc corners from the corresponding circle
144465837Sbostic
north()144565837Sbostic position arc_object::north()
144665837Sbostic {
144765837Sbostic position result(cent);
144865837Sbostic result.y += rad;
144965837Sbostic return result;
145065837Sbostic }
145165837Sbostic
south()145265837Sbostic position arc_object::south()
145365837Sbostic {
145465837Sbostic position result(cent);
145565837Sbostic result.y -= rad;
145665837Sbostic return result;
145765837Sbostic }
145865837Sbostic
east()145965837Sbostic position arc_object::east()
146065837Sbostic {
146165837Sbostic position result(cent);
146265837Sbostic result.x += rad;
146365837Sbostic return result;
146465837Sbostic }
146565837Sbostic
west()146665837Sbostic position arc_object::west()
146765837Sbostic {
146865837Sbostic position result(cent);
146965837Sbostic result.x -= rad;
147065837Sbostic return result;
147165837Sbostic }
147265837Sbostic
north_east()147365837Sbostic position arc_object::north_east()
147465837Sbostic {
147565837Sbostic position result(cent);
147665837Sbostic result.x += rad/M_SQRT2;
147765837Sbostic result.y += rad/M_SQRT2;
147865837Sbostic return result;
147965837Sbostic }
148065837Sbostic
north_west()148165837Sbostic position arc_object::north_west()
148265837Sbostic {
148365837Sbostic position result(cent);
148465837Sbostic result.x -= rad/M_SQRT2;
148565837Sbostic result.y += rad/M_SQRT2;
148665837Sbostic return result;
148765837Sbostic }
148865837Sbostic
south_east()148965837Sbostic position arc_object::south_east()
149065837Sbostic {
149165837Sbostic position result(cent);
149265837Sbostic result.x += rad/M_SQRT2;
149365837Sbostic result.y -= rad/M_SQRT2;
149465837Sbostic return result;
149565837Sbostic }
149665837Sbostic
south_west()149765837Sbostic position arc_object::south_west()
149865837Sbostic {
149965837Sbostic position result(cent);
150065837Sbostic result.x -= rad/M_SQRT2;
150165837Sbostic result.y -= rad/M_SQRT2;
150265837Sbostic return result;
150365837Sbostic }
150465837Sbostic
150565837Sbostic
print()150665837Sbostic void arc_object::print()
150765837Sbostic {
150865837Sbostic if (lt.type == line_type::invisible)
150965837Sbostic return;
151065837Sbostic if (clockwise)
151165837Sbostic out->arc(en, cent, strt, lt);
151265837Sbostic else
151365837Sbostic out->arc(strt, cent, en, lt);
151465837Sbostic if (arrow_at_start) {
151565837Sbostic position c = cent - strt;
151665837Sbostic draw_arrow(strt,
151765837Sbostic (clockwise ? position(c.y, -c.x) : position(-c.y, c.x)),
151865837Sbostic aht, lt);
151965837Sbostic }
152065837Sbostic if (arrow_at_end) {
152165837Sbostic position e = en - cent;
152265837Sbostic draw_arrow(en,
152365837Sbostic (clockwise ? position(e.y, -e.x) : position(-e.y, e.x)),
152465837Sbostic aht, lt);
152565837Sbostic }
152665837Sbostic }
152765837Sbostic
max(double a,double b)152865837Sbostic inline double max(double a, double b)
152965837Sbostic {
153065837Sbostic return a > b ? a : b;
153165837Sbostic }
153265837Sbostic
update_bounding_box(bounding_box * p)153365837Sbostic void arc_object::update_bounding_box(bounding_box *p)
153465837Sbostic {
153565837Sbostic p->encompass(strt);
153665837Sbostic p->encompass(en);
153765837Sbostic position start_offset = strt - cent;
153865837Sbostic if (start_offset.x == 0.0 && start_offset.y == 0.0)
153965837Sbostic return;
154065837Sbostic position end_offset = en - cent;
154165837Sbostic if (end_offset.x == 0.0 && end_offset.y == 0.0)
154265837Sbostic return;
154365837Sbostic double start_quad = atan2(start_offset.y, start_offset.x)/(M_PI/2.0);
154465837Sbostic double end_quad = atan2(end_offset.y, end_offset.x)/(M_PI/2.0);
154565837Sbostic if (clockwise) {
154665837Sbostic double temp = start_quad;
154765837Sbostic start_quad = end_quad;
154865837Sbostic end_quad = temp;
154965837Sbostic }
155065837Sbostic if (start_quad < 0.0)
155165837Sbostic start_quad += 4.0;
155265837Sbostic while (end_quad <= start_quad)
155365837Sbostic end_quad += 4.0;
155465837Sbostic double radius = max(hypot(start_offset), hypot(end_offset));
155565837Sbostic for (int q = int(start_quad) + 1; q < end_quad; q++) {
155665837Sbostic position offset;
155765837Sbostic switch (q % 4) {
155865837Sbostic case 0:
155965837Sbostic offset.x = radius;
156065837Sbostic break;
156165837Sbostic case 1:
156265837Sbostic offset.y = radius;
156365837Sbostic break;
156465837Sbostic case 2:
156565837Sbostic offset.x = -radius;
156665837Sbostic break;
156765837Sbostic case 3:
156865837Sbostic offset.y = -radius;
156965837Sbostic break;
157065837Sbostic }
157165837Sbostic p->encompass(cent + offset);
157265837Sbostic }
157365837Sbostic }
157465837Sbostic
157565837Sbostic // We ignore the with attribute. The at attribute always refers to the center.
157665837Sbostic
make_arc(position * curpos,direction * dirp)157765837Sbostic linear_object *object_spec::make_arc(position *curpos, direction *dirp)
157865837Sbostic {
157965837Sbostic *dirp = dir;
158065837Sbostic int cw = (flags & IS_CLOCKWISE) != 0;
158165837Sbostic // compute the start
158265837Sbostic position startpos;
158365837Sbostic if (flags & HAS_FROM)
158465837Sbostic startpos = from;
158565837Sbostic else
158665837Sbostic startpos = *curpos;
158765837Sbostic if (!(flags & HAS_RADIUS))
158865837Sbostic lookup_variable("arcrad", &radius);
158965837Sbostic // compute the end
159065837Sbostic position endpos;
159165837Sbostic if (flags & HAS_TO)
159265837Sbostic endpos = to;
159365837Sbostic else {
159465837Sbostic position m(radius, radius);
159565837Sbostic // Adjust the signs.
159665837Sbostic if (cw) {
159765837Sbostic if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION)
159865837Sbostic m.x = -m.x;
159965837Sbostic if (dir == DOWN_DIRECTION || dir == RIGHT_DIRECTION)
160065837Sbostic m.y = -m.y;
160165837Sbostic *dirp = direction((dir + 3) % 4);
160265837Sbostic }
160365837Sbostic else {
160465837Sbostic if (dir == UP_DIRECTION || dir == LEFT_DIRECTION)
160565837Sbostic m.x = -m.x;
160665837Sbostic if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION)
160765837Sbostic m.y = -m.y;
160865837Sbostic *dirp = direction((dir + 1) % 4);
160965837Sbostic }
161065837Sbostic endpos = startpos + m;
161165837Sbostic }
161265837Sbostic // compute the center
161365837Sbostic position centerpos;
161465837Sbostic if (flags & HAS_AT)
161565837Sbostic centerpos = at;
161665837Sbostic else if (startpos == endpos)
161765837Sbostic centerpos = startpos;
161865837Sbostic else {
161965837Sbostic position h = (endpos - startpos)/2.0;
162065837Sbostic double d = hypot(h);
162165837Sbostic if (radius <= 0)
162265837Sbostic radius = .25;
162365837Sbostic // make the radius big enough
162465837Sbostic while (radius < d)
162565837Sbostic radius *= 2.0;
162665837Sbostic double alpha = acos(d/radius);
162765837Sbostic double theta = atan2(h.y, h.x);
162865837Sbostic if (cw)
162965837Sbostic theta -= alpha;
163065837Sbostic else
163165837Sbostic theta += alpha;
163265837Sbostic centerpos = position(cos(theta), sin(theta))*radius + startpos;
163365837Sbostic }
163465837Sbostic arc_object *p = new arc_object(cw, startpos, endpos, centerpos);
163565837Sbostic *curpos = endpos;
163665837Sbostic return p;
163765837Sbostic }
163865837Sbostic
make_linear(position * curpos,direction * dirp)163965837Sbostic graphic_object *object_spec::make_linear(position *curpos, direction *dirp)
164065837Sbostic {
164165837Sbostic linear_object *obj;
164265837Sbostic if (type == ARC_OBJECT)
164365837Sbostic obj = make_arc(curpos, dirp);
164465837Sbostic else
164565837Sbostic obj = make_line(curpos, dirp);
164665837Sbostic if (type == ARROW_OBJECT
164765837Sbostic && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD)) == 0)
164865837Sbostic flags |= HAS_RIGHT_ARROW_HEAD;
164965837Sbostic if (obj && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD))) {
165065837Sbostic arrow_head_type a;
165165837Sbostic int at_start = (flags & HAS_LEFT_ARROW_HEAD) != 0;
165265837Sbostic int at_end = (flags & HAS_RIGHT_ARROW_HEAD) != 0;
165365837Sbostic if (flags & HAS_HEIGHT)
165465837Sbostic a.height = height;
165565837Sbostic else
165665837Sbostic lookup_variable("arrowht", &a.height);
165765837Sbostic if (flags & HAS_WIDTH)
165865837Sbostic a.width = width;
165965837Sbostic else
166065837Sbostic lookup_variable("arrowwid", &a.width);
166165837Sbostic double solid;
166265837Sbostic lookup_variable("arrowhead", &solid);
166365837Sbostic a.solid = solid != 0.0;
166465837Sbostic obj->add_arrows(at_start, at_end, a);
166565837Sbostic }
166665837Sbostic return obj;
166765837Sbostic }
166865837Sbostic
make_object(position * curpos,direction * dirp)166965837Sbostic object *object_spec::make_object(position *curpos, direction *dirp)
167065837Sbostic {
167165837Sbostic graphic_object *obj = 0;
167265837Sbostic switch (type) {
167365837Sbostic case BLOCK_OBJECT:
167465837Sbostic obj = make_block(curpos, dirp);
167565837Sbostic break;
167665837Sbostic case BOX_OBJECT:
167765837Sbostic obj = make_box(curpos, dirp);
167865837Sbostic break;
167965837Sbostic case TEXT_OBJECT:
168065837Sbostic obj = make_text(curpos, dirp);
168165837Sbostic break;
168265837Sbostic case ELLIPSE_OBJECT:
168365837Sbostic obj = make_ellipse(curpos, dirp);
168465837Sbostic break;
168565837Sbostic case CIRCLE_OBJECT:
168665837Sbostic obj = make_circle(curpos, dirp);
168765837Sbostic break;
168865837Sbostic case MOVE_OBJECT:
168965837Sbostic obj = make_move(curpos, dirp);
169065837Sbostic break;
169165837Sbostic case ARC_OBJECT:
169265837Sbostic case LINE_OBJECT:
169365837Sbostic case SPLINE_OBJECT:
169465837Sbostic case ARROW_OBJECT:
169565837Sbostic obj = make_linear(curpos, dirp);
169665837Sbostic break;
169765837Sbostic case MARK_OBJECT:
169865837Sbostic case OTHER_OBJECT:
169965837Sbostic default:
170065837Sbostic assert(0);
170165837Sbostic break;
170265837Sbostic }
170365837Sbostic if (obj) {
170465837Sbostic if (flags & IS_INVISIBLE)
170565837Sbostic obj->set_invisible();
170665837Sbostic if (text != 0)
170765837Sbostic obj->add_text(text, (flags & IS_ALIGNED) != 0);
170865837Sbostic if (flags & IS_DOTTED)
170965837Sbostic obj->set_dotted(dash_width);
171065837Sbostic else if (flags & IS_DASHED)
171165837Sbostic obj->set_dashed(dash_width);
171265837Sbostic double th;
171365837Sbostic if (flags & HAS_THICKNESS)
171465837Sbostic th = thickness;
171565837Sbostic else
171665837Sbostic lookup_variable("linethick", &th);
171765837Sbostic obj->set_thickness(th);
171865837Sbostic if (flags & (IS_DEFAULT_FILLED|IS_FILLED)) {
171965837Sbostic if (flags & IS_DEFAULT_FILLED)
172065837Sbostic lookup_variable("fillval", &fill);
172165837Sbostic if (fill < 0.0)
172265837Sbostic error("bad fill value %1", fill);
172365837Sbostic else
172465837Sbostic obj->set_fill(fill);
172565837Sbostic }
172665837Sbostic }
172765837Sbostic return obj;
172865837Sbostic }
172965837Sbostic
173065837Sbostic struct string_list {
173165837Sbostic string_list *next;
173265837Sbostic char *str;
173365837Sbostic string_list(char *);
173465837Sbostic ~string_list();
173565837Sbostic };
173665837Sbostic
string_list(char * s)173765837Sbostic string_list::string_list(char *s)
173865837Sbostic : next(0), str(s)
173965837Sbostic {
174065837Sbostic }
174165837Sbostic
~string_list()174265837Sbostic string_list::~string_list()
174365837Sbostic {
174465837Sbostic a_delete str;
174565837Sbostic }
174665837Sbostic
174765837Sbostic /* A path is used to hold the argument to the with attribute. For example,
174865837Sbostic `.nw' or `.A.s' or `.A'. The major operation on a path is to take a
174965837Sbostic place and follow the path through the place to place within the place.
175065837Sbostic Note that `.A.B.C.sw' will work. */
175165837Sbostic
path(corner c)175265837Sbostic path::path(corner c)
175365837Sbostic : label_list(0), crn(c)
175465837Sbostic {
175565837Sbostic }
175665837Sbostic
path(char * l,corner c)175765837Sbostic path::path(char *l, corner c)
175865837Sbostic : crn(c)
175965837Sbostic {
176065837Sbostic label_list = new string_list(l);
176165837Sbostic }
176265837Sbostic
~path()176365837Sbostic path::~path()
176465837Sbostic {
176565837Sbostic while (label_list) {
176665837Sbostic string_list *tem = label_list;
176765837Sbostic label_list = label_list->next;
176865837Sbostic delete tem;
176965837Sbostic }
177065837Sbostic }
177165837Sbostic
append(corner c)177265837Sbostic void path::append(corner c)
177365837Sbostic {
177465837Sbostic assert(crn == 0);
177565837Sbostic crn = c;
177665837Sbostic }
177765837Sbostic
append(char * s)177865837Sbostic void path::append(char *s)
177965837Sbostic {
178065837Sbostic for (string_list **p = &label_list; *p; p = &(*p)->next)
178165837Sbostic ;
178265837Sbostic *p = new string_list(s);
178365837Sbostic }
178465837Sbostic
178565837Sbostic // return non-zero for success
178665837Sbostic
follow(const place & pl,place * result) const178765837Sbostic int path::follow(const place &pl, place *result) const
178865837Sbostic {
178965837Sbostic const place *p = &pl;
179065837Sbostic for (string_list *lb = label_list; lb; lb = lb->next)
179165837Sbostic if (p->obj == 0 || (p = p->obj->find_label(lb->str)) == 0) {
179265837Sbostic lex_error("object does not contain a place `%1'", lb->str);
179365837Sbostic return 0;
179465837Sbostic }
179565837Sbostic if (crn == 0 || p->obj == 0)
179665837Sbostic *result = *p;
179765837Sbostic else {
179865837Sbostic position pos = ((p->obj)->*(crn))();
179965837Sbostic result->x = pos.x;
180065837Sbostic result->y = pos.y;
180165837Sbostic result->obj = 0;
180265837Sbostic }
180365837Sbostic return 1;
180465837Sbostic }
180565837Sbostic
print_object_list(object * p)180665837Sbostic void print_object_list(object *p)
180765837Sbostic {
180865837Sbostic for (; p; p = p->next) {
180965837Sbostic p->print();
181065837Sbostic p->print_text();
181165837Sbostic }
181265837Sbostic }
181365837Sbostic
print_picture(object * obj)181465837Sbostic void print_picture(object *obj)
181565837Sbostic {
181665837Sbostic bounding_box bb;
181765837Sbostic for (object *p = obj; p; p = p->next)
181865837Sbostic p->update_bounding_box(&bb);
181965837Sbostic double scale;
182065837Sbostic lookup_variable("scale", &scale);
182165837Sbostic out->start_picture(scale, bb.ll, bb.ur);
182265837Sbostic print_object_list(obj);
182365837Sbostic out->finish_picture();
182465837Sbostic }
182565837Sbostic
1826