1*65837Sbostic // -*- C++ -*- 2*65837Sbostic /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. 3*65837Sbostic Written by James Clark (jjc@jclark.com) 4*65837Sbostic 5*65837Sbostic This file is part of groff. 6*65837Sbostic 7*65837Sbostic groff is free software; you can redistribute it and/or modify it under 8*65837Sbostic the terms of the GNU General Public License as published by the Free 9*65837Sbostic Software Foundation; either version 2, or (at your option) any later 10*65837Sbostic version. 11*65837Sbostic 12*65837Sbostic groff is distributed in the hope that it will be useful, but WITHOUT ANY 13*65837Sbostic WARRANTY; without even the implied warranty of MERCHANTABILITY or 14*65837Sbostic FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15*65837Sbostic for more details. 16*65837Sbostic 17*65837Sbostic You should have received a copy of the GNU General Public License along 18*65837Sbostic with groff; see the file COPYING. If not, write to the Free Software 19*65837Sbostic Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 20*65837Sbostic 21*65837Sbostic #include "pic.h" 22*65837Sbostic #include "ptable.h" 23*65837Sbostic #include "object.h" 24*65837Sbostic 25*65837Sbostic void print_object_list(object *); 26*65837Sbostic 27*65837Sbostic line_type::line_type() 28*65837Sbostic : type(solid), thickness(1.0) 29*65837Sbostic { 30*65837Sbostic } 31*65837Sbostic 32*65837Sbostic output::output() : desired_height(0.0), desired_width(0.0), args(0) 33*65837Sbostic { 34*65837Sbostic } 35*65837Sbostic 36*65837Sbostic output::~output() 37*65837Sbostic { 38*65837Sbostic a_delete args; 39*65837Sbostic } 40*65837Sbostic 41*65837Sbostic void output::set_desired_width_height(double wid, double ht) 42*65837Sbostic { 43*65837Sbostic desired_width = wid; 44*65837Sbostic desired_height = ht; 45*65837Sbostic } 46*65837Sbostic 47*65837Sbostic void output::set_args(const char *s) 48*65837Sbostic { 49*65837Sbostic a_delete args; 50*65837Sbostic if (s == 0 || *s == '\0') 51*65837Sbostic args = 0; 52*65837Sbostic else 53*65837Sbostic args = strsave(s); 54*65837Sbostic } 55*65837Sbostic 56*65837Sbostic void output::command(const char *, const char *, int) 57*65837Sbostic { 58*65837Sbostic } 59*65837Sbostic 60*65837Sbostic void output::set_location(const char *, int) 61*65837Sbostic { 62*65837Sbostic } 63*65837Sbostic 64*65837Sbostic int output::supports_filled_polygons() 65*65837Sbostic { 66*65837Sbostic return 0; 67*65837Sbostic } 68*65837Sbostic 69*65837Sbostic void output::begin_block(const position &, const position &) 70*65837Sbostic { 71*65837Sbostic } 72*65837Sbostic 73*65837Sbostic void output::end_block() 74*65837Sbostic { 75*65837Sbostic } 76*65837Sbostic 77*65837Sbostic double output::compute_scale(double sc, const position &ll, const position &ur) 78*65837Sbostic { 79*65837Sbostic distance dim = ur - ll; 80*65837Sbostic if (desired_width != 0.0 || desired_height != 0.0) { 81*65837Sbostic sc = 0.0; 82*65837Sbostic if (desired_width != 0.0) { 83*65837Sbostic if (dim.x == 0.0) 84*65837Sbostic error("width specified for picture with zero width"); 85*65837Sbostic else 86*65837Sbostic sc = dim.x/desired_width; 87*65837Sbostic } 88*65837Sbostic if (desired_height != 0.0) { 89*65837Sbostic if (dim.y == 0.0) 90*65837Sbostic error("height specified for picture with zero height"); 91*65837Sbostic else { 92*65837Sbostic double tem = dim.y/desired_height; 93*65837Sbostic if (tem > sc) 94*65837Sbostic sc = tem; 95*65837Sbostic } 96*65837Sbostic } 97*65837Sbostic return sc == 0.0 ? 1.0 : sc; 98*65837Sbostic } 99*65837Sbostic else { 100*65837Sbostic if (sc <= 0.0) 101*65837Sbostic sc = 1.0; 102*65837Sbostic distance sdim = dim/sc; 103*65837Sbostic double max_width = 0.0; 104*65837Sbostic lookup_variable("maxpswid", &max_width); 105*65837Sbostic double max_height = 0.0; 106*65837Sbostic lookup_variable("maxpsht", &max_height); 107*65837Sbostic if ((max_width > 0.0 && sdim.x > max_width) 108*65837Sbostic || (max_height > 0.0 && sdim.y > max_height)) { 109*65837Sbostic double xscale = dim.x/max_width; 110*65837Sbostic double yscale = dim.y/max_height; 111*65837Sbostic return xscale > yscale ? xscale : yscale; 112*65837Sbostic } 113*65837Sbostic else 114*65837Sbostic return sc; 115*65837Sbostic } 116*65837Sbostic } 117*65837Sbostic 118*65837Sbostic position::position(const place &pl) 119*65837Sbostic { 120*65837Sbostic if (pl.obj != 0) { 121*65837Sbostic // Use two statements to work around bug in SGI C++. 122*65837Sbostic object *tem = pl.obj; 123*65837Sbostic *this = tem->origin(); 124*65837Sbostic } 125*65837Sbostic else { 126*65837Sbostic x = pl.x; 127*65837Sbostic y = pl.y; 128*65837Sbostic } 129*65837Sbostic } 130*65837Sbostic 131*65837Sbostic position::position() : x(0.0), y(0.0) 132*65837Sbostic { 133*65837Sbostic } 134*65837Sbostic 135*65837Sbostic position::position(double a, double b) : x(a), y(b) 136*65837Sbostic { 137*65837Sbostic } 138*65837Sbostic 139*65837Sbostic 140*65837Sbostic int operator==(const position &a, const position &b) 141*65837Sbostic { 142*65837Sbostic return a.x == b.x && a.y == b.y; 143*65837Sbostic } 144*65837Sbostic 145*65837Sbostic int operator!=(const position &a, const position &b) 146*65837Sbostic { 147*65837Sbostic return a.x != b.x || a.y != b.y; 148*65837Sbostic } 149*65837Sbostic 150*65837Sbostic position &position::operator+=(const position &a) 151*65837Sbostic { 152*65837Sbostic x += a.x; 153*65837Sbostic y += a.y; 154*65837Sbostic return *this; 155*65837Sbostic } 156*65837Sbostic 157*65837Sbostic position &position::operator-=(const position &a) 158*65837Sbostic { 159*65837Sbostic x -= a.x; 160*65837Sbostic y -= a.y; 161*65837Sbostic return *this; 162*65837Sbostic } 163*65837Sbostic 164*65837Sbostic position &position::operator*=(double a) 165*65837Sbostic { 166*65837Sbostic x *= a; 167*65837Sbostic y *= a; 168*65837Sbostic return *this; 169*65837Sbostic } 170*65837Sbostic 171*65837Sbostic position &position::operator/=(double a) 172*65837Sbostic { 173*65837Sbostic x /= a; 174*65837Sbostic y /= a; 175*65837Sbostic return *this; 176*65837Sbostic } 177*65837Sbostic 178*65837Sbostic position operator-(const position &a) 179*65837Sbostic { 180*65837Sbostic return position(-a.x, -a.y); 181*65837Sbostic } 182*65837Sbostic 183*65837Sbostic position operator+(const position &a, const position &b) 184*65837Sbostic { 185*65837Sbostic return position(a.x + b.x, a.y + b.y); 186*65837Sbostic } 187*65837Sbostic 188*65837Sbostic position operator-(const position &a, const position &b) 189*65837Sbostic { 190*65837Sbostic return position(a.x - b.x, a.y - b.y); 191*65837Sbostic } 192*65837Sbostic 193*65837Sbostic position operator/(const position &a, double n) 194*65837Sbostic { 195*65837Sbostic return position(a.x/n, a.y/n); 196*65837Sbostic } 197*65837Sbostic 198*65837Sbostic position operator*(const position &a, double n) 199*65837Sbostic { 200*65837Sbostic return position(a.x*n, a.y*n); 201*65837Sbostic } 202*65837Sbostic 203*65837Sbostic // dot product 204*65837Sbostic 205*65837Sbostic double operator*(const position &a, const position &b) 206*65837Sbostic { 207*65837Sbostic return a.x*b.x + a.y*b.y; 208*65837Sbostic } 209*65837Sbostic 210*65837Sbostic double hypot(const position &a) 211*65837Sbostic { 212*65837Sbostic return hypot(a.x, a.y); 213*65837Sbostic } 214*65837Sbostic 215*65837Sbostic struct arrow_head_type { 216*65837Sbostic double height; 217*65837Sbostic double width; 218*65837Sbostic int solid; 219*65837Sbostic }; 220*65837Sbostic 221*65837Sbostic void draw_arrow(const position &pos, const distance &dir, 222*65837Sbostic const arrow_head_type &aht, const line_type <) 223*65837Sbostic { 224*65837Sbostic double hyp = hypot(dir); 225*65837Sbostic if (hyp == 0.0) { 226*65837Sbostic error("cannot draw arrow on object with zero length"); 227*65837Sbostic return; 228*65837Sbostic } 229*65837Sbostic position base = -dir; 230*65837Sbostic base *= aht.height/hyp; 231*65837Sbostic position n(dir.y, -dir.x); 232*65837Sbostic n *= aht.width/(hyp*2.0); 233*65837Sbostic line_type slt = lt; 234*65837Sbostic slt.type = line_type::solid; 235*65837Sbostic if (aht.solid && out->supports_filled_polygons()) { 236*65837Sbostic position v[3]; 237*65837Sbostic v[0] = pos; 238*65837Sbostic v[1] = pos + base + n; 239*65837Sbostic v[2] = pos + base - n; 240*65837Sbostic // A value > 1 means fill with the current color. 241*65837Sbostic out->polygon(v, 3, slt, 2.0); 242*65837Sbostic } 243*65837Sbostic else { 244*65837Sbostic position v[2]; 245*65837Sbostic v[0] = pos; 246*65837Sbostic v[1] = pos + base + n; 247*65837Sbostic out->line(pos + base - n, v, 2, slt); 248*65837Sbostic } 249*65837Sbostic } 250*65837Sbostic 251*65837Sbostic object::object() : prev(0), next(0) 252*65837Sbostic { 253*65837Sbostic } 254*65837Sbostic 255*65837Sbostic object::~object() 256*65837Sbostic { 257*65837Sbostic } 258*65837Sbostic 259*65837Sbostic void object::move_by(const position &) 260*65837Sbostic { 261*65837Sbostic } 262*65837Sbostic 263*65837Sbostic void object::print() 264*65837Sbostic { 265*65837Sbostic } 266*65837Sbostic 267*65837Sbostic void object::print_text() 268*65837Sbostic { 269*65837Sbostic } 270*65837Sbostic 271*65837Sbostic int object::blank() 272*65837Sbostic { 273*65837Sbostic return 0; 274*65837Sbostic } 275*65837Sbostic 276*65837Sbostic struct bounding_box { 277*65837Sbostic int blank; 278*65837Sbostic position ll; 279*65837Sbostic position ur; 280*65837Sbostic 281*65837Sbostic bounding_box(); 282*65837Sbostic void encompass(const position &); 283*65837Sbostic }; 284*65837Sbostic 285*65837Sbostic bounding_box::bounding_box() 286*65837Sbostic : blank(1) 287*65837Sbostic { 288*65837Sbostic } 289*65837Sbostic 290*65837Sbostic void bounding_box::encompass(const position &pos) 291*65837Sbostic { 292*65837Sbostic if (blank) { 293*65837Sbostic ll = pos; 294*65837Sbostic ur = pos; 295*65837Sbostic blank = 0; 296*65837Sbostic } 297*65837Sbostic else { 298*65837Sbostic if (pos.x < ll.x) 299*65837Sbostic ll.x = pos.x; 300*65837Sbostic if (pos.y < ll.y) 301*65837Sbostic ll.y = pos.y; 302*65837Sbostic if (pos.x > ur.x) 303*65837Sbostic ur.x = pos.x; 304*65837Sbostic if (pos.y > ur.y) 305*65837Sbostic ur.y = pos.y; 306*65837Sbostic } 307*65837Sbostic } 308*65837Sbostic 309*65837Sbostic void object::update_bounding_box(bounding_box *) 310*65837Sbostic { 311*65837Sbostic } 312*65837Sbostic 313*65837Sbostic position object::origin() 314*65837Sbostic { 315*65837Sbostic return position(0.0,0.0); 316*65837Sbostic } 317*65837Sbostic 318*65837Sbostic position object::north() 319*65837Sbostic { 320*65837Sbostic return origin(); 321*65837Sbostic } 322*65837Sbostic 323*65837Sbostic position object::south() 324*65837Sbostic { 325*65837Sbostic return origin(); 326*65837Sbostic } 327*65837Sbostic 328*65837Sbostic position object::east() 329*65837Sbostic { 330*65837Sbostic return origin(); 331*65837Sbostic } 332*65837Sbostic 333*65837Sbostic position object::west() 334*65837Sbostic { 335*65837Sbostic return origin(); 336*65837Sbostic } 337*65837Sbostic 338*65837Sbostic position object::north_east() 339*65837Sbostic { 340*65837Sbostic return origin(); 341*65837Sbostic } 342*65837Sbostic 343*65837Sbostic position object::north_west() 344*65837Sbostic { 345*65837Sbostic return origin(); 346*65837Sbostic } 347*65837Sbostic 348*65837Sbostic position object::south_east() 349*65837Sbostic { 350*65837Sbostic return origin(); 351*65837Sbostic } 352*65837Sbostic 353*65837Sbostic position object::south_west() 354*65837Sbostic { 355*65837Sbostic return origin(); 356*65837Sbostic } 357*65837Sbostic 358*65837Sbostic position object::start() 359*65837Sbostic { 360*65837Sbostic return origin(); 361*65837Sbostic } 362*65837Sbostic 363*65837Sbostic position object::end() 364*65837Sbostic { 365*65837Sbostic return origin(); 366*65837Sbostic } 367*65837Sbostic 368*65837Sbostic position object::center() 369*65837Sbostic { 370*65837Sbostic return origin(); 371*65837Sbostic } 372*65837Sbostic 373*65837Sbostic double object::width() 374*65837Sbostic { 375*65837Sbostic return 0.0; 376*65837Sbostic } 377*65837Sbostic 378*65837Sbostic double object::radius() 379*65837Sbostic { 380*65837Sbostic return 0.0; 381*65837Sbostic } 382*65837Sbostic 383*65837Sbostic double object::height() 384*65837Sbostic { 385*65837Sbostic return 0.0; 386*65837Sbostic } 387*65837Sbostic 388*65837Sbostic place *object::find_label(const char *) 389*65837Sbostic { 390*65837Sbostic return 0; 391*65837Sbostic } 392*65837Sbostic 393*65837Sbostic segment::segment(const position &a, int n, segment *p) 394*65837Sbostic : pos(a), is_absolute(n), next(p) 395*65837Sbostic { 396*65837Sbostic } 397*65837Sbostic 398*65837Sbostic text_item::text_item(char *t, const char *fn, int ln) 399*65837Sbostic : filename(fn), lineno(ln), text(t), next(0) 400*65837Sbostic { 401*65837Sbostic adj.h = CENTER_ADJUST; 402*65837Sbostic adj.v = NONE_ADJUST; 403*65837Sbostic } 404*65837Sbostic 405*65837Sbostic text_item::~text_item() 406*65837Sbostic { 407*65837Sbostic a_delete text; 408*65837Sbostic } 409*65837Sbostic 410*65837Sbostic object_spec::object_spec(object_type t) : type(t) 411*65837Sbostic { 412*65837Sbostic flags = 0; 413*65837Sbostic tbl = 0; 414*65837Sbostic segment_list = 0; 415*65837Sbostic segment_width = segment_height = 0.0; 416*65837Sbostic segment_is_absolute = 0; 417*65837Sbostic text = 0; 418*65837Sbostic with = 0; 419*65837Sbostic dir = RIGHT_DIRECTION; 420*65837Sbostic } 421*65837Sbostic 422*65837Sbostic object_spec::~object_spec() 423*65837Sbostic { 424*65837Sbostic delete tbl; 425*65837Sbostic while (segment_list != 0) { 426*65837Sbostic segment *tem = segment_list; 427*65837Sbostic segment_list = segment_list->next; 428*65837Sbostic delete tem; 429*65837Sbostic } 430*65837Sbostic object *p = oblist.head; 431*65837Sbostic while (p != 0) { 432*65837Sbostic object *tem = p; 433*65837Sbostic p = p->next; 434*65837Sbostic delete tem; 435*65837Sbostic } 436*65837Sbostic while (text != 0) { 437*65837Sbostic text_item *tem = text; 438*65837Sbostic text = text->next; 439*65837Sbostic delete tem; 440*65837Sbostic } 441*65837Sbostic delete with; 442*65837Sbostic } 443*65837Sbostic 444*65837Sbostic class command_object : public object { 445*65837Sbostic char *s; 446*65837Sbostic const char *filename; 447*65837Sbostic int lineno; 448*65837Sbostic public: 449*65837Sbostic command_object(char *, const char *, int); 450*65837Sbostic ~command_object(); 451*65837Sbostic object_type type() { return OTHER_OBJECT; } 452*65837Sbostic void print(); 453*65837Sbostic }; 454*65837Sbostic 455*65837Sbostic command_object::command_object(char *p, const char *fn, int ln) 456*65837Sbostic : s(p), filename(fn), lineno(ln) 457*65837Sbostic { 458*65837Sbostic } 459*65837Sbostic 460*65837Sbostic command_object::~command_object() 461*65837Sbostic { 462*65837Sbostic a_delete s; 463*65837Sbostic } 464*65837Sbostic 465*65837Sbostic void command_object::print() 466*65837Sbostic { 467*65837Sbostic out->command(s, filename, lineno); 468*65837Sbostic } 469*65837Sbostic 470*65837Sbostic object *make_command_object(char *s, const char *fn, int ln) 471*65837Sbostic { 472*65837Sbostic return new command_object(s, fn, ln); 473*65837Sbostic } 474*65837Sbostic 475*65837Sbostic class mark_object : public object { 476*65837Sbostic public: 477*65837Sbostic mark_object(); 478*65837Sbostic object_type type(); 479*65837Sbostic }; 480*65837Sbostic 481*65837Sbostic object *make_mark_object() 482*65837Sbostic { 483*65837Sbostic return new mark_object(); 484*65837Sbostic } 485*65837Sbostic 486*65837Sbostic mark_object::mark_object() 487*65837Sbostic { 488*65837Sbostic } 489*65837Sbostic 490*65837Sbostic object_type mark_object::type() 491*65837Sbostic { 492*65837Sbostic return MARK_OBJECT; 493*65837Sbostic } 494*65837Sbostic 495*65837Sbostic object_list::object_list() : head(0), tail(0) 496*65837Sbostic { 497*65837Sbostic } 498*65837Sbostic 499*65837Sbostic void object_list::append(object *obj) 500*65837Sbostic { 501*65837Sbostic if (tail == 0) { 502*65837Sbostic obj->next = obj->prev = 0; 503*65837Sbostic head = tail = obj; 504*65837Sbostic } 505*65837Sbostic else { 506*65837Sbostic obj->prev = tail; 507*65837Sbostic obj->next = 0; 508*65837Sbostic tail->next = obj; 509*65837Sbostic tail = obj; 510*65837Sbostic } 511*65837Sbostic } 512*65837Sbostic 513*65837Sbostic void object_list::wrap_up_block(object_list *ol) 514*65837Sbostic { 515*65837Sbostic for (object *p = tail; p && p->type() != MARK_OBJECT; p = p->prev) 516*65837Sbostic ; 517*65837Sbostic assert(p != 0); 518*65837Sbostic ol->head = p->next; 519*65837Sbostic if (ol->head) { 520*65837Sbostic ol->tail = tail; 521*65837Sbostic ol->head->prev = 0; 522*65837Sbostic } 523*65837Sbostic else 524*65837Sbostic ol->tail = 0; 525*65837Sbostic tail = p->prev; 526*65837Sbostic if (tail) 527*65837Sbostic tail->next = 0; 528*65837Sbostic else 529*65837Sbostic head = 0; 530*65837Sbostic delete p; 531*65837Sbostic } 532*65837Sbostic 533*65837Sbostic text_piece::text_piece() 534*65837Sbostic : text(0), filename(0), lineno(-1) 535*65837Sbostic { 536*65837Sbostic adj.h = CENTER_ADJUST; 537*65837Sbostic adj.v = NONE_ADJUST; 538*65837Sbostic } 539*65837Sbostic 540*65837Sbostic text_piece::~text_piece() 541*65837Sbostic { 542*65837Sbostic a_delete text; 543*65837Sbostic } 544*65837Sbostic 545*65837Sbostic class graphic_object : public object { 546*65837Sbostic int ntext; 547*65837Sbostic text_piece *text; 548*65837Sbostic int aligned; 549*65837Sbostic protected: 550*65837Sbostic line_type lt; 551*65837Sbostic public: 552*65837Sbostic graphic_object(); 553*65837Sbostic ~graphic_object(); 554*65837Sbostic object_type type() = 0; 555*65837Sbostic void print_text(); 556*65837Sbostic void add_text(text_item *, int); 557*65837Sbostic void set_dotted(double); 558*65837Sbostic void set_dashed(double); 559*65837Sbostic void set_thickness(double); 560*65837Sbostic void set_invisible(); 561*65837Sbostic virtual void set_fill(double); 562*65837Sbostic }; 563*65837Sbostic 564*65837Sbostic graphic_object::graphic_object() : ntext(0), text(0), aligned(0) 565*65837Sbostic { 566*65837Sbostic } 567*65837Sbostic 568*65837Sbostic void graphic_object::set_dotted(double wid) 569*65837Sbostic { 570*65837Sbostic lt.type = line_type::dotted; 571*65837Sbostic lt.dash_width = wid; 572*65837Sbostic } 573*65837Sbostic 574*65837Sbostic void graphic_object::set_dashed(double wid) 575*65837Sbostic { 576*65837Sbostic lt.type = line_type::dashed; 577*65837Sbostic lt.dash_width = wid; 578*65837Sbostic } 579*65837Sbostic 580*65837Sbostic void graphic_object::set_thickness(double th) 581*65837Sbostic { 582*65837Sbostic lt.thickness = th; 583*65837Sbostic } 584*65837Sbostic 585*65837Sbostic void graphic_object::set_fill(double) 586*65837Sbostic { 587*65837Sbostic } 588*65837Sbostic 589*65837Sbostic void graphic_object::set_invisible() 590*65837Sbostic { 591*65837Sbostic lt.type = line_type::invisible; 592*65837Sbostic } 593*65837Sbostic 594*65837Sbostic void graphic_object::add_text(text_item *t, int a) 595*65837Sbostic { 596*65837Sbostic aligned = a; 597*65837Sbostic int len = 0; 598*65837Sbostic for (text_item *p = t; p; p = p->next) 599*65837Sbostic len++; 600*65837Sbostic if (len == 0) 601*65837Sbostic text = 0; 602*65837Sbostic else { 603*65837Sbostic text = new text_piece[len]; 604*65837Sbostic for (p = t, len = 0; p; p = p->next, len++) { 605*65837Sbostic text[len].text = p->text; 606*65837Sbostic p->text = 0; 607*65837Sbostic text[len].adj = p->adj; 608*65837Sbostic text[len].filename = p->filename; 609*65837Sbostic text[len].lineno = p->lineno; 610*65837Sbostic } 611*65837Sbostic } 612*65837Sbostic ntext = len; 613*65837Sbostic } 614*65837Sbostic 615*65837Sbostic void graphic_object::print_text() 616*65837Sbostic { 617*65837Sbostic double angle = 0.0; 618*65837Sbostic if (aligned) { 619*65837Sbostic position d(end() - start()); 620*65837Sbostic if (d.x != 0.0 || d.y != 0.0) 621*65837Sbostic angle = atan2(d.y, d.x); 622*65837Sbostic } 623*65837Sbostic if (text != 0) 624*65837Sbostic out->text(center(), text, ntext, angle); 625*65837Sbostic } 626*65837Sbostic 627*65837Sbostic graphic_object::~graphic_object() 628*65837Sbostic { 629*65837Sbostic if (text) 630*65837Sbostic ad_delete(ntext) text; 631*65837Sbostic } 632*65837Sbostic 633*65837Sbostic class rectangle_object : public graphic_object { 634*65837Sbostic protected: 635*65837Sbostic position cent; 636*65837Sbostic position dim; 637*65837Sbostic public: 638*65837Sbostic rectangle_object(const position &); 639*65837Sbostic double width() { return dim.x; } 640*65837Sbostic double height() { return dim.y; } 641*65837Sbostic position origin() { return cent; } 642*65837Sbostic position center() { return cent; } 643*65837Sbostic position north() { return position(cent.x, cent.y + dim.y/2.0); } 644*65837Sbostic position south() { return position(cent.x, cent.y - dim.y/2.0); } 645*65837Sbostic position east() { return position(cent.x + dim.x/2.0, cent.y); } 646*65837Sbostic position west() { return position(cent.x - dim.x/2.0, cent.y); } 647*65837Sbostic position north_east() { return position(cent.x + dim.x/2.0, cent.y + dim.y/2.0); } 648*65837Sbostic position north_west() { return position(cent.x - dim.x/2.0, cent.y + dim.y/2.0); } 649*65837Sbostic position south_east() { return position(cent.x + dim.x/2.0, cent.y - dim.y/2.0); } 650*65837Sbostic position south_west() { return position(cent.x - dim.x/2.0, cent.y - dim.y/2.0); } 651*65837Sbostic object_type type() = 0; 652*65837Sbostic void update_bounding_box(bounding_box *); 653*65837Sbostic void move_by(const position &); 654*65837Sbostic }; 655*65837Sbostic 656*65837Sbostic rectangle_object::rectangle_object(const position &d) 657*65837Sbostic : dim(d) 658*65837Sbostic { 659*65837Sbostic } 660*65837Sbostic 661*65837Sbostic void rectangle_object::update_bounding_box(bounding_box *p) 662*65837Sbostic { 663*65837Sbostic p->encompass(cent - dim/2.0); 664*65837Sbostic p->encompass(cent + dim/2.0); 665*65837Sbostic } 666*65837Sbostic 667*65837Sbostic void rectangle_object::move_by(const position &a) 668*65837Sbostic { 669*65837Sbostic cent += a; 670*65837Sbostic } 671*65837Sbostic 672*65837Sbostic class closed_object : public rectangle_object { 673*65837Sbostic public: 674*65837Sbostic closed_object(const position &); 675*65837Sbostic object_type type() = 0; 676*65837Sbostic void set_fill(double); 677*65837Sbostic protected: 678*65837Sbostic double fill; // < 0 if not filled 679*65837Sbostic }; 680*65837Sbostic 681*65837Sbostic closed_object::closed_object(const position &pos) 682*65837Sbostic : rectangle_object(pos), fill(-1.0) 683*65837Sbostic { 684*65837Sbostic } 685*65837Sbostic 686*65837Sbostic void closed_object::set_fill(double f) 687*65837Sbostic { 688*65837Sbostic assert(f >= 0.0); 689*65837Sbostic fill = f; 690*65837Sbostic } 691*65837Sbostic 692*65837Sbostic 693*65837Sbostic class box_object : public closed_object { 694*65837Sbostic double xrad; 695*65837Sbostic double yrad; 696*65837Sbostic public: 697*65837Sbostic box_object(const position &, double); 698*65837Sbostic object_type type() { return BOX_OBJECT; } 699*65837Sbostic void print(); 700*65837Sbostic position north_east(); 701*65837Sbostic position north_west(); 702*65837Sbostic position south_east(); 703*65837Sbostic position south_west(); 704*65837Sbostic }; 705*65837Sbostic 706*65837Sbostic box_object::box_object(const position &pos, double r) 707*65837Sbostic : closed_object(pos), xrad(dim.x > 0 ? r : -r), yrad(dim.y > 0 ? r : -r) 708*65837Sbostic { 709*65837Sbostic } 710*65837Sbostic 711*65837Sbostic const double CHOP_FACTOR = 1.0 - 1.0/M_SQRT2; 712*65837Sbostic 713*65837Sbostic position box_object::north_east() 714*65837Sbostic { 715*65837Sbostic return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad, 716*65837Sbostic cent.y + dim.y/2.0 - CHOP_FACTOR*yrad); 717*65837Sbostic } 718*65837Sbostic 719*65837Sbostic position box_object::north_west() 720*65837Sbostic { 721*65837Sbostic return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad, 722*65837Sbostic cent.y + dim.y/2.0 - CHOP_FACTOR*yrad); 723*65837Sbostic } 724*65837Sbostic 725*65837Sbostic position box_object::south_east() 726*65837Sbostic { 727*65837Sbostic return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad, 728*65837Sbostic cent.y - dim.y/2.0 + CHOP_FACTOR*yrad); 729*65837Sbostic } 730*65837Sbostic 731*65837Sbostic position box_object::south_west() 732*65837Sbostic { 733*65837Sbostic return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad, 734*65837Sbostic cent.y - dim.y/2.0 + CHOP_FACTOR*yrad); 735*65837Sbostic } 736*65837Sbostic 737*65837Sbostic void box_object::print() 738*65837Sbostic { 739*65837Sbostic if (lt.type == line_type::invisible && fill < 0.0) 740*65837Sbostic return; 741*65837Sbostic if (xrad == 0.0) { 742*65837Sbostic distance dim2 = dim/2.0; 743*65837Sbostic position vec[4]; 744*65837Sbostic vec[0] = cent + position(dim2.x, -dim2.y); 745*65837Sbostic vec[1] = cent + position(dim2.x, dim2.y); 746*65837Sbostic vec[2] = cent + position(-dim2.x, dim2.y); 747*65837Sbostic vec[3] = cent + position(-dim2.x, -dim2.y); 748*65837Sbostic out->polygon(vec, 4, lt, fill); 749*65837Sbostic } 750*65837Sbostic else { 751*65837Sbostic distance abs_dim(fabs(dim.x), fabs(dim.y)); 752*65837Sbostic out->rounded_box(cent, abs_dim, fabs(xrad), lt, fill); 753*65837Sbostic } 754*65837Sbostic } 755*65837Sbostic 756*65837Sbostic graphic_object *object_spec::make_box(position *curpos, direction *dirp) 757*65837Sbostic { 758*65837Sbostic static double last_box_height; 759*65837Sbostic static double last_box_width; 760*65837Sbostic static double last_box_radius; 761*65837Sbostic static int have_last_box = 0; 762*65837Sbostic if (!(flags & HAS_HEIGHT)) { 763*65837Sbostic if ((flags & IS_SAME) && have_last_box) 764*65837Sbostic height = last_box_height; 765*65837Sbostic else 766*65837Sbostic lookup_variable("boxht", &height); 767*65837Sbostic } 768*65837Sbostic if (!(flags & HAS_WIDTH)) { 769*65837Sbostic if ((flags & IS_SAME) && have_last_box) 770*65837Sbostic width = last_box_width; 771*65837Sbostic else 772*65837Sbostic lookup_variable("boxwid", &width); 773*65837Sbostic } 774*65837Sbostic if (!(flags & HAS_RADIUS)) { 775*65837Sbostic if ((flags & IS_SAME) && have_last_box) 776*65837Sbostic radius = last_box_radius; 777*65837Sbostic else 778*65837Sbostic lookup_variable("boxrad", &radius); 779*65837Sbostic } 780*65837Sbostic last_box_width = width; 781*65837Sbostic last_box_height = height; 782*65837Sbostic last_box_radius = radius; 783*65837Sbostic have_last_box = 1; 784*65837Sbostic radius = fabs(radius); 785*65837Sbostic if (radius*2.0 > fabs(width)) 786*65837Sbostic radius = fabs(width/2.0); 787*65837Sbostic if (radius*2.0 > fabs(height)) 788*65837Sbostic radius = fabs(height/2.0); 789*65837Sbostic box_object *p = new box_object(position(width, height), radius); 790*65837Sbostic if (!position_rectangle(p, curpos, dirp)) { 791*65837Sbostic delete p; 792*65837Sbostic p = 0; 793*65837Sbostic } 794*65837Sbostic return p; 795*65837Sbostic } 796*65837Sbostic 797*65837Sbostic // return non-zero for success 798*65837Sbostic 799*65837Sbostic int object_spec::position_rectangle(rectangle_object *p, 800*65837Sbostic position *curpos, direction *dirp) 801*65837Sbostic { 802*65837Sbostic position pos; 803*65837Sbostic dir = *dirp; // ignore any direction in attribute list 804*65837Sbostic position motion; 805*65837Sbostic switch (dir) { 806*65837Sbostic case UP_DIRECTION: 807*65837Sbostic motion.y = p->height()/2.0; 808*65837Sbostic break; 809*65837Sbostic case DOWN_DIRECTION: 810*65837Sbostic motion.y = -p->height()/2.0; 811*65837Sbostic break; 812*65837Sbostic case LEFT_DIRECTION: 813*65837Sbostic motion.x = -p->width()/2.0; 814*65837Sbostic break; 815*65837Sbostic case RIGHT_DIRECTION: 816*65837Sbostic motion.x = p->width()/2.0; 817*65837Sbostic break; 818*65837Sbostic default: 819*65837Sbostic assert(0); 820*65837Sbostic } 821*65837Sbostic if (flags & HAS_AT) { 822*65837Sbostic pos = at; 823*65837Sbostic if (flags & HAS_WITH) { 824*65837Sbostic place offset; 825*65837Sbostic place here; 826*65837Sbostic here.obj = p; 827*65837Sbostic if (!with->follow(here, &offset)) 828*65837Sbostic return 0; 829*65837Sbostic pos -= offset; 830*65837Sbostic } 831*65837Sbostic } 832*65837Sbostic else { 833*65837Sbostic pos = *curpos; 834*65837Sbostic pos += motion; 835*65837Sbostic } 836*65837Sbostic p->move_by(pos); 837*65837Sbostic pos += motion; 838*65837Sbostic *curpos = pos; 839*65837Sbostic return 1; 840*65837Sbostic } 841*65837Sbostic 842*65837Sbostic class block_object : public rectangle_object { 843*65837Sbostic object_list oblist; 844*65837Sbostic PTABLE(place) *tbl; 845*65837Sbostic public: 846*65837Sbostic block_object(const position &, const object_list &ol, PTABLE(place) *t); 847*65837Sbostic ~block_object(); 848*65837Sbostic place *find_label(const char *); 849*65837Sbostic object_type type(); 850*65837Sbostic void move_by(const position &); 851*65837Sbostic void print(); 852*65837Sbostic }; 853*65837Sbostic 854*65837Sbostic block_object::block_object(const position &d, const object_list &ol, 855*65837Sbostic PTABLE(place) *t) 856*65837Sbostic : oblist(ol), tbl(t), rectangle_object(d) 857*65837Sbostic { 858*65837Sbostic } 859*65837Sbostic 860*65837Sbostic block_object::~block_object() 861*65837Sbostic { 862*65837Sbostic delete tbl; 863*65837Sbostic object *p = oblist.head; 864*65837Sbostic while (p != 0) { 865*65837Sbostic object *tem = p; 866*65837Sbostic p = p->next; 867*65837Sbostic delete tem; 868*65837Sbostic } 869*65837Sbostic } 870*65837Sbostic 871*65837Sbostic void block_object::print() 872*65837Sbostic { 873*65837Sbostic out->begin_block(south_west(), north_east()); 874*65837Sbostic print_object_list(oblist.head); 875*65837Sbostic out->end_block(); 876*65837Sbostic } 877*65837Sbostic 878*65837Sbostic static void adjust_objectless_places(PTABLE(place) *tbl, const position &a) 879*65837Sbostic { 880*65837Sbostic // Adjust all the labels that aren't attached to objects. 881*65837Sbostic PTABLE_ITERATOR(place) iter(tbl); 882*65837Sbostic const char *key; 883*65837Sbostic place *pl; 884*65837Sbostic while (iter.next(&key, &pl)) 885*65837Sbostic if (key && csupper(key[0]) && pl->obj == 0) { 886*65837Sbostic pl->x += a.x; 887*65837Sbostic pl->y += a.y; 888*65837Sbostic } 889*65837Sbostic } 890*65837Sbostic 891*65837Sbostic void block_object::move_by(const position &a) 892*65837Sbostic { 893*65837Sbostic cent += a; 894*65837Sbostic for (object *p = oblist.head; p; p = p->next) 895*65837Sbostic p->move_by(a); 896*65837Sbostic adjust_objectless_places(tbl, a); 897*65837Sbostic } 898*65837Sbostic 899*65837Sbostic 900*65837Sbostic place *block_object::find_label(const char *name) 901*65837Sbostic { 902*65837Sbostic return tbl->lookup(name); 903*65837Sbostic } 904*65837Sbostic 905*65837Sbostic object_type block_object::type() 906*65837Sbostic { 907*65837Sbostic return BLOCK_OBJECT; 908*65837Sbostic } 909*65837Sbostic 910*65837Sbostic graphic_object *object_spec::make_block(position *curpos, direction *dirp) 911*65837Sbostic { 912*65837Sbostic bounding_box bb; 913*65837Sbostic for (object *p = oblist.head; p; p = p->next) 914*65837Sbostic p->update_bounding_box(&bb); 915*65837Sbostic position dim; 916*65837Sbostic if (!bb.blank) { 917*65837Sbostic position m = -(bb.ll + bb.ur)/2.0; 918*65837Sbostic for (object *p = oblist.head; p; p = p->next) 919*65837Sbostic p->move_by(m); 920*65837Sbostic adjust_objectless_places(tbl, m); 921*65837Sbostic dim = bb.ur - bb.ll; 922*65837Sbostic } 923*65837Sbostic if (flags & HAS_WIDTH) 924*65837Sbostic dim.x = width; 925*65837Sbostic if (flags & HAS_HEIGHT) 926*65837Sbostic dim.y = height; 927*65837Sbostic block_object *block = new block_object(dim, oblist, tbl); 928*65837Sbostic if (!position_rectangle(block, curpos, dirp)) { 929*65837Sbostic delete block; 930*65837Sbostic block = 0; 931*65837Sbostic } 932*65837Sbostic tbl = 0; 933*65837Sbostic oblist.head = oblist.tail = 0; 934*65837Sbostic return block; 935*65837Sbostic } 936*65837Sbostic 937*65837Sbostic class text_object : public rectangle_object { 938*65837Sbostic public: 939*65837Sbostic text_object(const position &); 940*65837Sbostic object_type type() { return TEXT_OBJECT; } 941*65837Sbostic }; 942*65837Sbostic 943*65837Sbostic text_object::text_object(const position &d) 944*65837Sbostic : rectangle_object(d) 945*65837Sbostic { 946*65837Sbostic } 947*65837Sbostic 948*65837Sbostic graphic_object *object_spec::make_text(position *curpos, direction *dirp) 949*65837Sbostic { 950*65837Sbostic if (!(flags & HAS_HEIGHT)) { 951*65837Sbostic lookup_variable("textht", &height); 952*65837Sbostic int nitems = 0; 953*65837Sbostic for (text_item *t = text; t; t = t->next) 954*65837Sbostic nitems++; 955*65837Sbostic height *= nitems; 956*65837Sbostic } 957*65837Sbostic if (!(flags & HAS_WIDTH)) 958*65837Sbostic lookup_variable("textwid", &width); 959*65837Sbostic text_object *p = new text_object(position(width, height)); 960*65837Sbostic if (!position_rectangle(p, curpos, dirp)) { 961*65837Sbostic delete p; 962*65837Sbostic p = 0; 963*65837Sbostic } 964*65837Sbostic return p; 965*65837Sbostic } 966*65837Sbostic 967*65837Sbostic 968*65837Sbostic class ellipse_object : public closed_object { 969*65837Sbostic public: 970*65837Sbostic ellipse_object(const position &); 971*65837Sbostic position north_east() { return position(cent.x + dim.x/(M_SQRT2*2.0), 972*65837Sbostic cent.y + dim.y/(M_SQRT2*2.0)); } 973*65837Sbostic position north_west() { return position(cent.x - dim.x/(M_SQRT2*2.0), 974*65837Sbostic cent.y + dim.y/(M_SQRT2*2.0)); } 975*65837Sbostic position south_east() { return position(cent.x + dim.x/(M_SQRT2*2.0), 976*65837Sbostic cent.y - dim.y/(M_SQRT2*2.0)); } 977*65837Sbostic position south_west() { return position(cent.x - dim.x/(M_SQRT2*2.0), 978*65837Sbostic cent.y - dim.y/(M_SQRT2*2.0)); } 979*65837Sbostic double radius() { return dim.x/2.0; } 980*65837Sbostic object_type type() { return ELLIPSE_OBJECT; } 981*65837Sbostic void print(); 982*65837Sbostic }; 983*65837Sbostic 984*65837Sbostic ellipse_object::ellipse_object(const position &d) 985*65837Sbostic : closed_object(d) 986*65837Sbostic { 987*65837Sbostic } 988*65837Sbostic 989*65837Sbostic void ellipse_object::print() 990*65837Sbostic { 991*65837Sbostic if (lt.type == line_type::invisible && fill < 0.0) 992*65837Sbostic return; 993*65837Sbostic out->ellipse(cent, dim, lt, fill); 994*65837Sbostic } 995*65837Sbostic 996*65837Sbostic graphic_object *object_spec::make_ellipse(position *curpos, direction *dirp) 997*65837Sbostic { 998*65837Sbostic static double last_ellipse_height; 999*65837Sbostic static double last_ellipse_width; 1000*65837Sbostic static int have_last_ellipse = 0; 1001*65837Sbostic if (!(flags & HAS_HEIGHT)) { 1002*65837Sbostic if ((flags & IS_SAME) && have_last_ellipse) 1003*65837Sbostic height = last_ellipse_height; 1004*65837Sbostic else 1005*65837Sbostic lookup_variable("ellipseht", &height); 1006*65837Sbostic } 1007*65837Sbostic if (!(flags & HAS_WIDTH)) { 1008*65837Sbostic if ((flags & IS_SAME) && have_last_ellipse) 1009*65837Sbostic width = last_ellipse_width; 1010*65837Sbostic else 1011*65837Sbostic lookup_variable("ellipsewid", &width); 1012*65837Sbostic } 1013*65837Sbostic last_ellipse_width = width; 1014*65837Sbostic last_ellipse_height = height; 1015*65837Sbostic have_last_ellipse = 1; 1016*65837Sbostic ellipse_object *p = new ellipse_object(position(width, height)); 1017*65837Sbostic if (!position_rectangle(p, curpos, dirp)) { 1018*65837Sbostic delete p; 1019*65837Sbostic return 0; 1020*65837Sbostic } 1021*65837Sbostic return p; 1022*65837Sbostic } 1023*65837Sbostic 1024*65837Sbostic class circle_object : public ellipse_object { 1025*65837Sbostic public: 1026*65837Sbostic circle_object(double); 1027*65837Sbostic object_type type() { return CIRCLE_OBJECT; } 1028*65837Sbostic void print(); 1029*65837Sbostic }; 1030*65837Sbostic 1031*65837Sbostic circle_object::circle_object(double diam) 1032*65837Sbostic : ellipse_object(position(diam, diam)) 1033*65837Sbostic { 1034*65837Sbostic } 1035*65837Sbostic 1036*65837Sbostic void circle_object::print() 1037*65837Sbostic { 1038*65837Sbostic if (lt.type == line_type::invisible && fill < 0.0) 1039*65837Sbostic return; 1040*65837Sbostic out->circle(cent, dim.x/2.0, lt, fill); 1041*65837Sbostic } 1042*65837Sbostic 1043*65837Sbostic graphic_object *object_spec::make_circle(position *curpos, direction *dirp) 1044*65837Sbostic { 1045*65837Sbostic static double last_circle_radius; 1046*65837Sbostic static int have_last_circle = 0; 1047*65837Sbostic if (!(flags & HAS_RADIUS)) { 1048*65837Sbostic if ((flags & IS_SAME) && have_last_circle) 1049*65837Sbostic radius = last_circle_radius; 1050*65837Sbostic else 1051*65837Sbostic lookup_variable("circlerad", &radius); 1052*65837Sbostic } 1053*65837Sbostic last_circle_radius = radius; 1054*65837Sbostic have_last_circle = 1; 1055*65837Sbostic circle_object *p = new circle_object(radius*2.0); 1056*65837Sbostic if (!position_rectangle(p, curpos, dirp)) { 1057*65837Sbostic delete p; 1058*65837Sbostic return 0; 1059*65837Sbostic } 1060*65837Sbostic return p; 1061*65837Sbostic } 1062*65837Sbostic 1063*65837Sbostic class move_object : public graphic_object { 1064*65837Sbostic position strt; 1065*65837Sbostic position en; 1066*65837Sbostic public: 1067*65837Sbostic move_object(const position &s, const position &e); 1068*65837Sbostic position origin() { return en; } 1069*65837Sbostic object_type type() { return MOVE_OBJECT; } 1070*65837Sbostic void update_bounding_box(bounding_box *); 1071*65837Sbostic void move_by(const position &); 1072*65837Sbostic }; 1073*65837Sbostic 1074*65837Sbostic move_object::move_object(const position &s, const position &e) 1075*65837Sbostic : strt(s), en(e) 1076*65837Sbostic { 1077*65837Sbostic } 1078*65837Sbostic 1079*65837Sbostic void move_object::update_bounding_box(bounding_box *p) 1080*65837Sbostic { 1081*65837Sbostic p->encompass(strt); 1082*65837Sbostic p->encompass(en); 1083*65837Sbostic } 1084*65837Sbostic 1085*65837Sbostic void move_object::move_by(const position &a) 1086*65837Sbostic { 1087*65837Sbostic strt += a; 1088*65837Sbostic en += a; 1089*65837Sbostic } 1090*65837Sbostic 1091*65837Sbostic graphic_object *object_spec::make_move(position *curpos, direction *dirp) 1092*65837Sbostic { 1093*65837Sbostic static position last_move; 1094*65837Sbostic static int have_last_move = 0; 1095*65837Sbostic *dirp = dir; 1096*65837Sbostic // No need to look at at since `at' attribute sets `from' attribute. 1097*65837Sbostic position startpos = (flags & HAS_FROM) ? from : *curpos; 1098*65837Sbostic if (!(flags & HAS_SEGMENT)) { 1099*65837Sbostic if ((flags && IS_SAME) && have_last_move) 1100*65837Sbostic segment_pos = last_move; 1101*65837Sbostic else { 1102*65837Sbostic switch (dir) { 1103*65837Sbostic case UP_DIRECTION: 1104*65837Sbostic segment_pos.y = segment_height; 1105*65837Sbostic break; 1106*65837Sbostic case DOWN_DIRECTION: 1107*65837Sbostic segment_pos.y = -segment_height; 1108*65837Sbostic break; 1109*65837Sbostic case LEFT_DIRECTION: 1110*65837Sbostic segment_pos.x = -segment_width; 1111*65837Sbostic break; 1112*65837Sbostic case RIGHT_DIRECTION: 1113*65837Sbostic segment_pos.x = segment_width; 1114*65837Sbostic break; 1115*65837Sbostic default: 1116*65837Sbostic assert(0); 1117*65837Sbostic } 1118*65837Sbostic } 1119*65837Sbostic } 1120*65837Sbostic segment_list = new segment(segment_pos, segment_is_absolute, segment_list); 1121*65837Sbostic // Reverse the segment_list so that it's in forward order. 1122*65837Sbostic segment *old = segment_list; 1123*65837Sbostic segment_list = 0; 1124*65837Sbostic while (old != 0) { 1125*65837Sbostic segment *tem = old->next; 1126*65837Sbostic old->next = segment_list; 1127*65837Sbostic segment_list = old; 1128*65837Sbostic old = tem; 1129*65837Sbostic } 1130*65837Sbostic // Compute the end position. 1131*65837Sbostic position endpos = startpos; 1132*65837Sbostic for (segment *s = segment_list; s; s = s->next) 1133*65837Sbostic if (s->is_absolute) 1134*65837Sbostic endpos = s->pos; 1135*65837Sbostic else 1136*65837Sbostic endpos += s->pos; 1137*65837Sbostic have_last_move = 1; 1138*65837Sbostic last_move = endpos - startpos; 1139*65837Sbostic move_object *p = new move_object(startpos, endpos); 1140*65837Sbostic *curpos = endpos; 1141*65837Sbostic return p; 1142*65837Sbostic } 1143*65837Sbostic 1144*65837Sbostic class linear_object : public graphic_object { 1145*65837Sbostic protected: 1146*65837Sbostic char arrow_at_start; 1147*65837Sbostic char arrow_at_end; 1148*65837Sbostic arrow_head_type aht; 1149*65837Sbostic position strt; 1150*65837Sbostic position en; 1151*65837Sbostic public: 1152*65837Sbostic linear_object(const position &s, const position &e); 1153*65837Sbostic position start() { return strt; } 1154*65837Sbostic position end() { return en; } 1155*65837Sbostic void move_by(const position &); 1156*65837Sbostic void update_bounding_box(bounding_box *) = 0; 1157*65837Sbostic object_type type() = 0; 1158*65837Sbostic void add_arrows(int at_start, int at_end, const arrow_head_type &); 1159*65837Sbostic }; 1160*65837Sbostic 1161*65837Sbostic class line_object : public linear_object { 1162*65837Sbostic protected: 1163*65837Sbostic position *v; 1164*65837Sbostic int n; 1165*65837Sbostic public: 1166*65837Sbostic line_object(const position &s, const position &e, position *, int); 1167*65837Sbostic ~line_object(); 1168*65837Sbostic position origin() { return strt; } 1169*65837Sbostic position center() { return (strt + en)/2.0; } 1170*65837Sbostic position north() { return (en.y - strt.y) > 0 ? en : strt; } 1171*65837Sbostic position south() { return (en.y - strt.y) < 0 ? en : strt; } 1172*65837Sbostic position east() { return (en.x - strt.x) > 0 ? en : strt; } 1173*65837Sbostic position west() { return (en.x - strt.x) < 0 ? en : strt; } 1174*65837Sbostic object_type type() { return LINE_OBJECT; } 1175*65837Sbostic void update_bounding_box(bounding_box *); 1176*65837Sbostic void print(); 1177*65837Sbostic void move_by(const position &); 1178*65837Sbostic }; 1179*65837Sbostic 1180*65837Sbostic class arrow_object : public line_object { 1181*65837Sbostic public: 1182*65837Sbostic arrow_object(const position &, const position &, position *, int); 1183*65837Sbostic object_type type() { return ARROW_OBJECT; } 1184*65837Sbostic }; 1185*65837Sbostic 1186*65837Sbostic class spline_object : public line_object { 1187*65837Sbostic public: 1188*65837Sbostic spline_object(const position &, const position &, position *, int); 1189*65837Sbostic object_type type() { return SPLINE_OBJECT; } 1190*65837Sbostic void print(); 1191*65837Sbostic void update_bounding_box(bounding_box *); 1192*65837Sbostic }; 1193*65837Sbostic 1194*65837Sbostic linear_object::linear_object(const position &s, const position &e) 1195*65837Sbostic : strt(s), en(e), arrow_at_start(0), arrow_at_end(0) 1196*65837Sbostic { 1197*65837Sbostic } 1198*65837Sbostic 1199*65837Sbostic void linear_object::move_by(const position &a) 1200*65837Sbostic { 1201*65837Sbostic strt += a; 1202*65837Sbostic en += a; 1203*65837Sbostic } 1204*65837Sbostic 1205*65837Sbostic void linear_object::add_arrows(int at_start, int at_end, 1206*65837Sbostic const arrow_head_type &a) 1207*65837Sbostic { 1208*65837Sbostic arrow_at_start = at_start; 1209*65837Sbostic arrow_at_end = at_end; 1210*65837Sbostic aht = a; 1211*65837Sbostic } 1212*65837Sbostic 1213*65837Sbostic line_object::line_object(const position &s, const position &e, 1214*65837Sbostic position *p, int i) 1215*65837Sbostic : v(p), n(i), linear_object(s, e) 1216*65837Sbostic { 1217*65837Sbostic } 1218*65837Sbostic 1219*65837Sbostic void line_object::print() 1220*65837Sbostic { 1221*65837Sbostic if (lt.type == line_type::invisible) 1222*65837Sbostic return; 1223*65837Sbostic out->line(strt, v, n, lt); 1224*65837Sbostic if (arrow_at_start) 1225*65837Sbostic draw_arrow(strt, strt-v[0], aht, lt); 1226*65837Sbostic if (arrow_at_end) 1227*65837Sbostic draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt); 1228*65837Sbostic } 1229*65837Sbostic 1230*65837Sbostic void line_object::update_bounding_box(bounding_box *p) 1231*65837Sbostic { 1232*65837Sbostic p->encompass(strt); 1233*65837Sbostic for (int i = 0; i < n; i++) 1234*65837Sbostic p->encompass(v[i]); 1235*65837Sbostic } 1236*65837Sbostic 1237*65837Sbostic void line_object::move_by(const position &pos) 1238*65837Sbostic { 1239*65837Sbostic linear_object::move_by(pos); 1240*65837Sbostic for (int i = 0; i < n; i++) 1241*65837Sbostic v[i] += pos; 1242*65837Sbostic } 1243*65837Sbostic 1244*65837Sbostic void spline_object::update_bounding_box(bounding_box *p) 1245*65837Sbostic { 1246*65837Sbostic p->encompass(strt); 1247*65837Sbostic p->encompass(en); 1248*65837Sbostic /* 1249*65837Sbostic 1250*65837Sbostic If 1251*65837Sbostic 1252*65837Sbostic p1 = q1/2 + q2/2 1253*65837Sbostic p2 = q1/6 + q2*5/6 1254*65837Sbostic p3 = q2*5/6 + q3/6 1255*65837Sbostic p4 = q2/2 + q3/2 1256*65837Sbostic [ the points for the Bezier cubic ] 1257*65837Sbostic 1258*65837Sbostic and 1259*65837Sbostic 1260*65837Sbostic t = .5 1261*65837Sbostic 1262*65837Sbostic then 1263*65837Sbostic 1264*65837Sbostic (1-t)^3*p1 + 3*t*(t - 1)^2*p2 + 3*t^2*(1-t)*p3 + t^3*p4 1265*65837Sbostic [ the equation for the Bezier cubic ] 1266*65837Sbostic 1267*65837Sbostic = .125*q1 + .75*q2 + .125*q3 1268*65837Sbostic 1269*65837Sbostic */ 1270*65837Sbostic for (int i = 1; i < n; i++) 1271*65837Sbostic p->encompass((i == 1 ? strt : v[i-2])*.125 + v[i-1]*.75 + v[i]*.125); 1272*65837Sbostic } 1273*65837Sbostic 1274*65837Sbostic arrow_object::arrow_object(const position &s, const position &e, 1275*65837Sbostic position *p, int i) 1276*65837Sbostic : line_object(s, e, p, i) 1277*65837Sbostic { 1278*65837Sbostic } 1279*65837Sbostic 1280*65837Sbostic spline_object::spline_object(const position &s, const position &e, 1281*65837Sbostic position *p, int i) 1282*65837Sbostic : line_object(s, e, p, i) 1283*65837Sbostic { 1284*65837Sbostic } 1285*65837Sbostic 1286*65837Sbostic void spline_object::print() 1287*65837Sbostic { 1288*65837Sbostic if (lt.type == line_type::invisible) 1289*65837Sbostic return; 1290*65837Sbostic out->spline(strt, v, n, lt); 1291*65837Sbostic if (arrow_at_start) 1292*65837Sbostic draw_arrow(strt, strt-v[0], aht, lt); 1293*65837Sbostic if (arrow_at_end) 1294*65837Sbostic draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt); 1295*65837Sbostic } 1296*65837Sbostic 1297*65837Sbostic line_object::~line_object() 1298*65837Sbostic { 1299*65837Sbostic a_delete v; 1300*65837Sbostic } 1301*65837Sbostic 1302*65837Sbostic linear_object *object_spec::make_line(position *curpos, direction *dirp) 1303*65837Sbostic { 1304*65837Sbostic static position last_line; 1305*65837Sbostic static int have_last_line = 0; 1306*65837Sbostic *dirp = dir; 1307*65837Sbostic // No need to look at at since `at' attribute sets `from' attribute. 1308*65837Sbostic position startpos = (flags & HAS_FROM) ? from : *curpos; 1309*65837Sbostic if (!(flags & HAS_SEGMENT)) { 1310*65837Sbostic if ((flags & IS_SAME) && (type == LINE_OBJECT || type == ARROW_OBJECT) 1311*65837Sbostic && have_last_line) 1312*65837Sbostic segment_pos = last_line; 1313*65837Sbostic else 1314*65837Sbostic switch (dir) { 1315*65837Sbostic case UP_DIRECTION: 1316*65837Sbostic segment_pos.y = segment_height; 1317*65837Sbostic break; 1318*65837Sbostic case DOWN_DIRECTION: 1319*65837Sbostic segment_pos.y = -segment_height; 1320*65837Sbostic break; 1321*65837Sbostic case LEFT_DIRECTION: 1322*65837Sbostic segment_pos.x = -segment_width; 1323*65837Sbostic break; 1324*65837Sbostic case RIGHT_DIRECTION: 1325*65837Sbostic segment_pos.x = segment_width; 1326*65837Sbostic break; 1327*65837Sbostic default: 1328*65837Sbostic assert(0); 1329*65837Sbostic } 1330*65837Sbostic } 1331*65837Sbostic segment_list = new segment(segment_pos, segment_is_absolute, segment_list); 1332*65837Sbostic // reverse the segment_list so that it's in forward order 1333*65837Sbostic segment *old = segment_list; 1334*65837Sbostic segment_list = 0; 1335*65837Sbostic while (old != 0) { 1336*65837Sbostic segment *tem = old->next; 1337*65837Sbostic old->next = segment_list; 1338*65837Sbostic segment_list = old; 1339*65837Sbostic old = tem; 1340*65837Sbostic } 1341*65837Sbostic // Absolutise all movements 1342*65837Sbostic position endpos = startpos; 1343*65837Sbostic int nsegments = 0; 1344*65837Sbostic for (segment *s = segment_list; s; s = s->next, nsegments++) 1345*65837Sbostic if (s->is_absolute) 1346*65837Sbostic endpos = s->pos; 1347*65837Sbostic else { 1348*65837Sbostic endpos += s->pos; 1349*65837Sbostic s->pos = endpos; 1350*65837Sbostic s->is_absolute = 1; // to avoid confusion 1351*65837Sbostic } 1352*65837Sbostic // handle chop 1353*65837Sbostic line_object *p = 0; 1354*65837Sbostic position *v = new position[nsegments]; 1355*65837Sbostic int i = 0; 1356*65837Sbostic for (s = segment_list; s; s = s->next, i++) 1357*65837Sbostic v[i] = s->pos; 1358*65837Sbostic if (flags & IS_DEFAULT_CHOPPED) { 1359*65837Sbostic lookup_variable("circlerad", &start_chop); 1360*65837Sbostic end_chop = start_chop; 1361*65837Sbostic flags |= IS_CHOPPED; 1362*65837Sbostic } 1363*65837Sbostic if (flags & IS_CHOPPED) { 1364*65837Sbostic position start_chop_vec, end_chop_vec; 1365*65837Sbostic if (start_chop != 0.0) { 1366*65837Sbostic start_chop_vec = v[0] - startpos; 1367*65837Sbostic start_chop_vec *= start_chop / hypot(start_chop_vec); 1368*65837Sbostic } 1369*65837Sbostic if (end_chop != 0.0) { 1370*65837Sbostic end_chop_vec = (v[nsegments - 1] 1371*65837Sbostic - (nsegments > 1 ? v[nsegments - 2] : startpos)); 1372*65837Sbostic end_chop_vec *= end_chop / hypot(end_chop_vec); 1373*65837Sbostic } 1374*65837Sbostic startpos += start_chop_vec; 1375*65837Sbostic v[nsegments - 1] -= end_chop_vec; 1376*65837Sbostic endpos -= end_chop_vec; 1377*65837Sbostic } 1378*65837Sbostic switch (type) { 1379*65837Sbostic case SPLINE_OBJECT: 1380*65837Sbostic p = new spline_object(startpos, endpos, v, nsegments); 1381*65837Sbostic break; 1382*65837Sbostic case ARROW_OBJECT: 1383*65837Sbostic p = new arrow_object(startpos, endpos, v, nsegments); 1384*65837Sbostic break; 1385*65837Sbostic case LINE_OBJECT: 1386*65837Sbostic p = new line_object(startpos, endpos, v, nsegments); 1387*65837Sbostic break; 1388*65837Sbostic default: 1389*65837Sbostic assert(0); 1390*65837Sbostic } 1391*65837Sbostic have_last_line = 1; 1392*65837Sbostic last_line = endpos - startpos; 1393*65837Sbostic *curpos = endpos; 1394*65837Sbostic return p; 1395*65837Sbostic } 1396*65837Sbostic 1397*65837Sbostic class arc_object : public linear_object { 1398*65837Sbostic int clockwise; 1399*65837Sbostic position cent; 1400*65837Sbostic double rad; 1401*65837Sbostic public: 1402*65837Sbostic arc_object(int, const position &, const position &, const position &); 1403*65837Sbostic position origin() { return cent; } 1404*65837Sbostic position center() { return cent; } 1405*65837Sbostic double radius() { return rad; } 1406*65837Sbostic position north(); 1407*65837Sbostic position south(); 1408*65837Sbostic position east(); 1409*65837Sbostic position west(); 1410*65837Sbostic position north_east(); 1411*65837Sbostic position north_west(); 1412*65837Sbostic position south_east(); 1413*65837Sbostic position south_west(); 1414*65837Sbostic void update_bounding_box(bounding_box *); 1415*65837Sbostic object_type type() { return ARC_OBJECT; } 1416*65837Sbostic void print(); 1417*65837Sbostic void move_by(const position &pos); 1418*65837Sbostic }; 1419*65837Sbostic 1420*65837Sbostic arc_object::arc_object(int cw, const position &s, const position &e, 1421*65837Sbostic const position &c) 1422*65837Sbostic : linear_object(s, e), clockwise(cw), cent(c) 1423*65837Sbostic { 1424*65837Sbostic rad = hypot(c - s); 1425*65837Sbostic } 1426*65837Sbostic 1427*65837Sbostic void arc_object::move_by(const position &pos) 1428*65837Sbostic { 1429*65837Sbostic linear_object::move_by(pos); 1430*65837Sbostic cent += pos; 1431*65837Sbostic } 1432*65837Sbostic 1433*65837Sbostic // we get arc corners from the corresponding circle 1434*65837Sbostic 1435*65837Sbostic position arc_object::north() 1436*65837Sbostic { 1437*65837Sbostic position result(cent); 1438*65837Sbostic result.y += rad; 1439*65837Sbostic return result; 1440*65837Sbostic } 1441*65837Sbostic 1442*65837Sbostic position arc_object::south() 1443*65837Sbostic { 1444*65837Sbostic position result(cent); 1445*65837Sbostic result.y -= rad; 1446*65837Sbostic return result; 1447*65837Sbostic } 1448*65837Sbostic 1449*65837Sbostic position arc_object::east() 1450*65837Sbostic { 1451*65837Sbostic position result(cent); 1452*65837Sbostic result.x += rad; 1453*65837Sbostic return result; 1454*65837Sbostic } 1455*65837Sbostic 1456*65837Sbostic position arc_object::west() 1457*65837Sbostic { 1458*65837Sbostic position result(cent); 1459*65837Sbostic result.x -= rad; 1460*65837Sbostic return result; 1461*65837Sbostic } 1462*65837Sbostic 1463*65837Sbostic position arc_object::north_east() 1464*65837Sbostic { 1465*65837Sbostic position result(cent); 1466*65837Sbostic result.x += rad/M_SQRT2; 1467*65837Sbostic result.y += rad/M_SQRT2; 1468*65837Sbostic return result; 1469*65837Sbostic } 1470*65837Sbostic 1471*65837Sbostic position arc_object::north_west() 1472*65837Sbostic { 1473*65837Sbostic position result(cent); 1474*65837Sbostic result.x -= rad/M_SQRT2; 1475*65837Sbostic result.y += rad/M_SQRT2; 1476*65837Sbostic return result; 1477*65837Sbostic } 1478*65837Sbostic 1479*65837Sbostic position arc_object::south_east() 1480*65837Sbostic { 1481*65837Sbostic position result(cent); 1482*65837Sbostic result.x += rad/M_SQRT2; 1483*65837Sbostic result.y -= rad/M_SQRT2; 1484*65837Sbostic return result; 1485*65837Sbostic } 1486*65837Sbostic 1487*65837Sbostic position arc_object::south_west() 1488*65837Sbostic { 1489*65837Sbostic position result(cent); 1490*65837Sbostic result.x -= rad/M_SQRT2; 1491*65837Sbostic result.y -= rad/M_SQRT2; 1492*65837Sbostic return result; 1493*65837Sbostic } 1494*65837Sbostic 1495*65837Sbostic 1496*65837Sbostic void arc_object::print() 1497*65837Sbostic { 1498*65837Sbostic if (lt.type == line_type::invisible) 1499*65837Sbostic return; 1500*65837Sbostic if (clockwise) 1501*65837Sbostic out->arc(en, cent, strt, lt); 1502*65837Sbostic else 1503*65837Sbostic out->arc(strt, cent, en, lt); 1504*65837Sbostic if (arrow_at_start) { 1505*65837Sbostic position c = cent - strt; 1506*65837Sbostic draw_arrow(strt, 1507*65837Sbostic (clockwise ? position(c.y, -c.x) : position(-c.y, c.x)), 1508*65837Sbostic aht, lt); 1509*65837Sbostic } 1510*65837Sbostic if (arrow_at_end) { 1511*65837Sbostic position e = en - cent; 1512*65837Sbostic draw_arrow(en, 1513*65837Sbostic (clockwise ? position(e.y, -e.x) : position(-e.y, e.x)), 1514*65837Sbostic aht, lt); 1515*65837Sbostic } 1516*65837Sbostic } 1517*65837Sbostic 1518*65837Sbostic inline double max(double a, double b) 1519*65837Sbostic { 1520*65837Sbostic return a > b ? a : b; 1521*65837Sbostic } 1522*65837Sbostic 1523*65837Sbostic void arc_object::update_bounding_box(bounding_box *p) 1524*65837Sbostic { 1525*65837Sbostic p->encompass(strt); 1526*65837Sbostic p->encompass(en); 1527*65837Sbostic position start_offset = strt - cent; 1528*65837Sbostic if (start_offset.x == 0.0 && start_offset.y == 0.0) 1529*65837Sbostic return; 1530*65837Sbostic position end_offset = en - cent; 1531*65837Sbostic if (end_offset.x == 0.0 && end_offset.y == 0.0) 1532*65837Sbostic return; 1533*65837Sbostic double start_quad = atan2(start_offset.y, start_offset.x)/(M_PI/2.0); 1534*65837Sbostic double end_quad = atan2(end_offset.y, end_offset.x)/(M_PI/2.0); 1535*65837Sbostic if (clockwise) { 1536*65837Sbostic double temp = start_quad; 1537*65837Sbostic start_quad = end_quad; 1538*65837Sbostic end_quad = temp; 1539*65837Sbostic } 1540*65837Sbostic if (start_quad < 0.0) 1541*65837Sbostic start_quad += 4.0; 1542*65837Sbostic while (end_quad <= start_quad) 1543*65837Sbostic end_quad += 4.0; 1544*65837Sbostic double radius = max(hypot(start_offset), hypot(end_offset)); 1545*65837Sbostic for (int q = int(start_quad) + 1; q < end_quad; q++) { 1546*65837Sbostic position offset; 1547*65837Sbostic switch (q % 4) { 1548*65837Sbostic case 0: 1549*65837Sbostic offset.x = radius; 1550*65837Sbostic break; 1551*65837Sbostic case 1: 1552*65837Sbostic offset.y = radius; 1553*65837Sbostic break; 1554*65837Sbostic case 2: 1555*65837Sbostic offset.x = -radius; 1556*65837Sbostic break; 1557*65837Sbostic case 3: 1558*65837Sbostic offset.y = -radius; 1559*65837Sbostic break; 1560*65837Sbostic } 1561*65837Sbostic p->encompass(cent + offset); 1562*65837Sbostic } 1563*65837Sbostic } 1564*65837Sbostic 1565*65837Sbostic // We ignore the with attribute. The at attribute always refers to the center. 1566*65837Sbostic 1567*65837Sbostic linear_object *object_spec::make_arc(position *curpos, direction *dirp) 1568*65837Sbostic { 1569*65837Sbostic *dirp = dir; 1570*65837Sbostic int cw = (flags & IS_CLOCKWISE) != 0; 1571*65837Sbostic // compute the start 1572*65837Sbostic position startpos; 1573*65837Sbostic if (flags & HAS_FROM) 1574*65837Sbostic startpos = from; 1575*65837Sbostic else 1576*65837Sbostic startpos = *curpos; 1577*65837Sbostic if (!(flags & HAS_RADIUS)) 1578*65837Sbostic lookup_variable("arcrad", &radius); 1579*65837Sbostic // compute the end 1580*65837Sbostic position endpos; 1581*65837Sbostic if (flags & HAS_TO) 1582*65837Sbostic endpos = to; 1583*65837Sbostic else { 1584*65837Sbostic position m(radius, radius); 1585*65837Sbostic // Adjust the signs. 1586*65837Sbostic if (cw) { 1587*65837Sbostic if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION) 1588*65837Sbostic m.x = -m.x; 1589*65837Sbostic if (dir == DOWN_DIRECTION || dir == RIGHT_DIRECTION) 1590*65837Sbostic m.y = -m.y; 1591*65837Sbostic *dirp = direction((dir + 3) % 4); 1592*65837Sbostic } 1593*65837Sbostic else { 1594*65837Sbostic if (dir == UP_DIRECTION || dir == LEFT_DIRECTION) 1595*65837Sbostic m.x = -m.x; 1596*65837Sbostic if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION) 1597*65837Sbostic m.y = -m.y; 1598*65837Sbostic *dirp = direction((dir + 1) % 4); 1599*65837Sbostic } 1600*65837Sbostic endpos = startpos + m; 1601*65837Sbostic } 1602*65837Sbostic // compute the center 1603*65837Sbostic position centerpos; 1604*65837Sbostic if (flags & HAS_AT) 1605*65837Sbostic centerpos = at; 1606*65837Sbostic else if (startpos == endpos) 1607*65837Sbostic centerpos = startpos; 1608*65837Sbostic else { 1609*65837Sbostic position h = (endpos - startpos)/2.0; 1610*65837Sbostic double d = hypot(h); 1611*65837Sbostic if (radius <= 0) 1612*65837Sbostic radius = .25; 1613*65837Sbostic // make the radius big enough 1614*65837Sbostic while (radius < d) 1615*65837Sbostic radius *= 2.0; 1616*65837Sbostic double alpha = acos(d/radius); 1617*65837Sbostic double theta = atan2(h.y, h.x); 1618*65837Sbostic if (cw) 1619*65837Sbostic theta -= alpha; 1620*65837Sbostic else 1621*65837Sbostic theta += alpha; 1622*65837Sbostic centerpos = position(cos(theta), sin(theta))*radius + startpos; 1623*65837Sbostic } 1624*65837Sbostic arc_object *p = new arc_object(cw, startpos, endpos, centerpos); 1625*65837Sbostic *curpos = endpos; 1626*65837Sbostic return p; 1627*65837Sbostic } 1628*65837Sbostic 1629*65837Sbostic graphic_object *object_spec::make_linear(position *curpos, direction *dirp) 1630*65837Sbostic { 1631*65837Sbostic linear_object *obj; 1632*65837Sbostic if (type == ARC_OBJECT) 1633*65837Sbostic obj = make_arc(curpos, dirp); 1634*65837Sbostic else 1635*65837Sbostic obj = make_line(curpos, dirp); 1636*65837Sbostic if (type == ARROW_OBJECT 1637*65837Sbostic && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD)) == 0) 1638*65837Sbostic flags |= HAS_RIGHT_ARROW_HEAD; 1639*65837Sbostic if (obj && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD))) { 1640*65837Sbostic arrow_head_type a; 1641*65837Sbostic int at_start = (flags & HAS_LEFT_ARROW_HEAD) != 0; 1642*65837Sbostic int at_end = (flags & HAS_RIGHT_ARROW_HEAD) != 0; 1643*65837Sbostic if (flags & HAS_HEIGHT) 1644*65837Sbostic a.height = height; 1645*65837Sbostic else 1646*65837Sbostic lookup_variable("arrowht", &a.height); 1647*65837Sbostic if (flags & HAS_WIDTH) 1648*65837Sbostic a.width = width; 1649*65837Sbostic else 1650*65837Sbostic lookup_variable("arrowwid", &a.width); 1651*65837Sbostic double solid; 1652*65837Sbostic lookup_variable("arrowhead", &solid); 1653*65837Sbostic a.solid = solid != 0.0; 1654*65837Sbostic obj->add_arrows(at_start, at_end, a); 1655*65837Sbostic } 1656*65837Sbostic return obj; 1657*65837Sbostic } 1658*65837Sbostic 1659*65837Sbostic object *object_spec::make_object(position *curpos, direction *dirp) 1660*65837Sbostic { 1661*65837Sbostic graphic_object *obj = 0; 1662*65837Sbostic switch (type) { 1663*65837Sbostic case BLOCK_OBJECT: 1664*65837Sbostic obj = make_block(curpos, dirp); 1665*65837Sbostic break; 1666*65837Sbostic case BOX_OBJECT: 1667*65837Sbostic obj = make_box(curpos, dirp); 1668*65837Sbostic break; 1669*65837Sbostic case TEXT_OBJECT: 1670*65837Sbostic obj = make_text(curpos, dirp); 1671*65837Sbostic break; 1672*65837Sbostic case ELLIPSE_OBJECT: 1673*65837Sbostic obj = make_ellipse(curpos, dirp); 1674*65837Sbostic break; 1675*65837Sbostic case CIRCLE_OBJECT: 1676*65837Sbostic obj = make_circle(curpos, dirp); 1677*65837Sbostic break; 1678*65837Sbostic case MOVE_OBJECT: 1679*65837Sbostic obj = make_move(curpos, dirp); 1680*65837Sbostic break; 1681*65837Sbostic case ARC_OBJECT: 1682*65837Sbostic case LINE_OBJECT: 1683*65837Sbostic case SPLINE_OBJECT: 1684*65837Sbostic case ARROW_OBJECT: 1685*65837Sbostic obj = make_linear(curpos, dirp); 1686*65837Sbostic break; 1687*65837Sbostic case MARK_OBJECT: 1688*65837Sbostic case OTHER_OBJECT: 1689*65837Sbostic default: 1690*65837Sbostic assert(0); 1691*65837Sbostic break; 1692*65837Sbostic } 1693*65837Sbostic if (obj) { 1694*65837Sbostic if (flags & IS_INVISIBLE) 1695*65837Sbostic obj->set_invisible(); 1696*65837Sbostic if (text != 0) 1697*65837Sbostic obj->add_text(text, (flags & IS_ALIGNED) != 0); 1698*65837Sbostic if (flags & IS_DOTTED) 1699*65837Sbostic obj->set_dotted(dash_width); 1700*65837Sbostic else if (flags & IS_DASHED) 1701*65837Sbostic obj->set_dashed(dash_width); 1702*65837Sbostic double th; 1703*65837Sbostic if (flags & HAS_THICKNESS) 1704*65837Sbostic th = thickness; 1705*65837Sbostic else 1706*65837Sbostic lookup_variable("linethick", &th); 1707*65837Sbostic obj->set_thickness(th); 1708*65837Sbostic if (flags & (IS_DEFAULT_FILLED|IS_FILLED)) { 1709*65837Sbostic if (flags & IS_DEFAULT_FILLED) 1710*65837Sbostic lookup_variable("fillval", &fill); 1711*65837Sbostic if (fill < 0.0) 1712*65837Sbostic error("bad fill value %1", fill); 1713*65837Sbostic else 1714*65837Sbostic obj->set_fill(fill); 1715*65837Sbostic } 1716*65837Sbostic } 1717*65837Sbostic return obj; 1718*65837Sbostic } 1719*65837Sbostic 1720*65837Sbostic struct string_list { 1721*65837Sbostic string_list *next; 1722*65837Sbostic char *str; 1723*65837Sbostic string_list(char *); 1724*65837Sbostic ~string_list(); 1725*65837Sbostic }; 1726*65837Sbostic 1727*65837Sbostic string_list::string_list(char *s) 1728*65837Sbostic : next(0), str(s) 1729*65837Sbostic { 1730*65837Sbostic } 1731*65837Sbostic 1732*65837Sbostic string_list::~string_list() 1733*65837Sbostic { 1734*65837Sbostic a_delete str; 1735*65837Sbostic } 1736*65837Sbostic 1737*65837Sbostic /* A path is used to hold the argument to the with attribute. For example, 1738*65837Sbostic `.nw' or `.A.s' or `.A'. The major operation on a path is to take a 1739*65837Sbostic place and follow the path through the place to place within the place. 1740*65837Sbostic Note that `.A.B.C.sw' will work. */ 1741*65837Sbostic 1742*65837Sbostic path::path(corner c) 1743*65837Sbostic : label_list(0), crn(c) 1744*65837Sbostic { 1745*65837Sbostic } 1746*65837Sbostic 1747*65837Sbostic path::path(char *l, corner c) 1748*65837Sbostic : crn(c) 1749*65837Sbostic { 1750*65837Sbostic label_list = new string_list(l); 1751*65837Sbostic } 1752*65837Sbostic 1753*65837Sbostic path::~path() 1754*65837Sbostic { 1755*65837Sbostic while (label_list) { 1756*65837Sbostic string_list *tem = label_list; 1757*65837Sbostic label_list = label_list->next; 1758*65837Sbostic delete tem; 1759*65837Sbostic } 1760*65837Sbostic } 1761*65837Sbostic 1762*65837Sbostic void path::append(corner c) 1763*65837Sbostic { 1764*65837Sbostic assert(crn == 0); 1765*65837Sbostic crn = c; 1766*65837Sbostic } 1767*65837Sbostic 1768*65837Sbostic void path::append(char *s) 1769*65837Sbostic { 1770*65837Sbostic for (string_list **p = &label_list; *p; p = &(*p)->next) 1771*65837Sbostic ; 1772*65837Sbostic *p = new string_list(s); 1773*65837Sbostic } 1774*65837Sbostic 1775*65837Sbostic // return non-zero for success 1776*65837Sbostic 1777*65837Sbostic int path::follow(const place &pl, place *result) const 1778*65837Sbostic { 1779*65837Sbostic const place *p = &pl; 1780*65837Sbostic for (string_list *lb = label_list; lb; lb = lb->next) 1781*65837Sbostic if (p->obj == 0 || (p = p->obj->find_label(lb->str)) == 0) { 1782*65837Sbostic lex_error("object does not contain a place `%1'", lb->str); 1783*65837Sbostic return 0; 1784*65837Sbostic } 1785*65837Sbostic if (crn == 0 || p->obj == 0) 1786*65837Sbostic *result = *p; 1787*65837Sbostic else { 1788*65837Sbostic position pos = ((p->obj)->*(crn))(); 1789*65837Sbostic result->x = pos.x; 1790*65837Sbostic result->y = pos.y; 1791*65837Sbostic result->obj = 0; 1792*65837Sbostic } 1793*65837Sbostic return 1; 1794*65837Sbostic } 1795*65837Sbostic 1796*65837Sbostic void print_object_list(object *p) 1797*65837Sbostic { 1798*65837Sbostic for (; p; p = p->next) { 1799*65837Sbostic p->print(); 1800*65837Sbostic p->print_text(); 1801*65837Sbostic } 1802*65837Sbostic } 1803*65837Sbostic 1804*65837Sbostic void print_picture(object *obj) 1805*65837Sbostic { 1806*65837Sbostic bounding_box bb; 1807*65837Sbostic for (object *p = obj; p; p = p->next) 1808*65837Sbostic p->update_bounding_box(&bb); 1809*65837Sbostic double scale; 1810*65837Sbostic lookup_variable("scale", &scale); 1811*65837Sbostic out->start_picture(scale, bb.ll, bb.ur); 1812*65837Sbostic print_object_list(obj); 1813*65837Sbostic out->finish_picture(); 1814*65837Sbostic } 1815*65837Sbostic 1816