123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067 |
- /* This file is part of the GNU plotutils package. Copyright (C) 1995,
- 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
- The GNU plotutils package is free software. You may redistribute it
- and/or modify it under the terms of the GNU General Public License as
- published by the Free Software foundation; either version 2, or (at your
- option) any later version.
- The GNU plotutils package is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with the GNU plotutils package; see the file COPYING. If not, write to
- the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
- Boston, MA 02110-1301, USA. */
- // This is almost the same as the object.cc file included in gpic, with
- // a lot of reformatting and commenting.
- // The only substantive change is to the arc_object::print method.
- // Previously, it distinguished clockwise arcs from counterclockwise simply
- // by interchanging the `start' and `end' points. This interfered with the
- // libplot driver, in particular with libplot's incremental path
- // constrution algorithm. Search for `PIC2PLOT' to see the alteration.
- #define PIC2PLOT
- #include "pic.h"
- #include "object.h"
- #include "output.h"
- // forward references
- static void print_object_list(object *p);
- line_type::line_type()
- : type(solid), thickness(1.0)
- {
- }
- //////////////////////////////////////////////////////////////////////
- // The base OUTPUT class, declared in output.h
- //////////////////////////////////////////////////////////////////////
- output::output() : args(0), desired_height(0.0), desired_width(0.0)
- {
- }
- output::~output()
- {
- a_delete args;
- }
- void
- output::command(const char *, const char *, int)
- {
- }
- void
- output::set_location(const char *, int)
- {
- }
- int
- output::supports_filled_polygons()
- {
- return 0;
- }
- void
- output::begin_block(const position &, const position &)
- {
- }
- void
- output::end_block()
- {
- }
- void
- output::set_desired_width_height(double wid, double ht)
- {
- desired_width = wid;
- desired_height = ht;
- }
- void
- output::set_args(const char *s)
- {
- a_delete args;
- if (s == 0 || *s == '\0')
- args = 0;
- else
- args = strsave(s);
- }
- double
- output::compute_scale(double sc, const position &ll, const position &ur)
- {
- distance dim = ur - ll;
- if (desired_width != 0.0 || desired_height != 0.0)
- {
- sc = 0.0;
- if (desired_width != 0.0)
- {
- if (dim.x == 0.0)
- error("width specified for picture with zero width");
- else
- sc = dim.x/desired_width;
- }
- if (desired_height != 0.0)
- {
- if (dim.y == 0.0)
- error("height specified for picture with zero height");
- else {
- double tem = dim.y/desired_height;
- if (tem > sc)
- sc = tem;
- }
- }
- return sc == 0.0 ? 1.0 : sc;
- }
- else
- // user didn't specify desired width or height on .PS line
- {
- if (sc <= 0.0)
- sc = 1.0;
- distance sdim = dim/sc;
- double max_width = 0.0;
- lookup_variable("maxpswid", &max_width);
- double max_height = 0.0;
- lookup_variable("maxpsht", &max_height);
- if ((max_width > 0.0 && sdim.x > max_width)
- || (max_height > 0.0 && sdim.y > max_height))
- {
- double xscale = dim.x/max_width;
- double yscale = dim.y/max_height;
- return xscale > yscale ? xscale : yscale;
- }
- else
- return sc;
- }
- }
- //////////////////////////////////////////////////////////////////////
- // The POSITION class, declared in libgroff/position.h
- //////////////////////////////////////////////////////////////////////
- position::position(const place &pl)
- {
- if (pl.obj != 0) {
- // Use two statements to work around bug in SGI C++.
- object *tem = pl.obj;
- *this = tem->origin();
- }
- else {
- x = pl.x;
- y = pl.y;
- }
- }
- position::position() : x(0.0), y(0.0)
- {
- }
- position::position(double a, double b) : x(a), y(b)
- {
- }
- int operator==(const position &a, const position &b)
- {
- return a.x == b.x && a.y == b.y;
- }
- int operator!=(const position &a, const position &b)
- {
- return a.x != b.x || a.y != b.y;
- }
- position &position::operator+=(const position &a)
- {
- x += a.x;
- y += a.y;
- return *this;
- }
- position &position::operator-=(const position &a)
- {
- x -= a.x;
- y -= a.y;
- return *this;
- }
- position &position::operator*=(double a)
- {
- x *= a;
- y *= a;
- return *this;
- }
- position &position::operator/=(double a)
- {
- x /= a;
- y /= a;
- return *this;
- }
- position operator-(const position &a)
- {
- return position(-a.x, -a.y);
- }
- position operator+(const position &a, const position &b)
- {
- return position(a.x + b.x, a.y + b.y);
- }
- position operator-(const position &a, const position &b)
- {
- return position(a.x - b.x, a.y - b.y);
- }
- position operator/(const position &a, double n)
- {
- return position(a.x/n, a.y/n);
- }
- position operator*(const position &a, double n)
- {
- return position(a.x*n, a.y*n);
- }
- // dot product
- double operator*(const position &a, const position &b)
- {
- return a.x*b.x + a.y*b.y;
- }
- double hypot(const position &a)
- {
- return hypot(a.x, a.y);
- }
- struct arrow_head_type
- {
- double height;
- double width;
- int solid;
- };
- static void
- draw_arrow(const position &pos, const distance &dir, const arrow_head_type &aht, const line_type <)
- {
- double hyp = hypot(dir);
- if (hyp == 0.0)
- {
- error("cannot draw arrow on object with zero length");
- return;
- }
- position base = -dir;
- base *= aht.height/hyp;
- position n(dir.y, -dir.x);
- n *= aht.width/(hyp*2.0);
- line_type slt = lt;
- slt.type = line_type::solid;
- if (aht.solid && out->supports_filled_polygons())
- {
- position v[3];
- v[0] = pos;
- v[1] = pos + base + n;
- v[2] = pos + base - n;
- // A value > 1 means fill with the current color.
- out->polygon(v, 3, slt, 2.0);
- }
- else
- {
- position v[2];
- v[0] = pos;
- v[1] = pos + base + n;
- out->line(pos + base - n, v, 2, slt);
- }
- }
- //////////////////////////////////////////////////////////////////////
- // The base OBJECT class, declared in object.h
- //////////////////////////////////////////////////////////////////////
- object::object() : prev(0), next(0)
- {
- }
- object::~object()
- {
- }
- void
- object::move_by(const position &)
- {
- }
- void
- object::print()
- {
- }
- void
- object::print_text()
- {
- }
- int
- object::blank()
- {
- return 0;
- }
- class bounding_box
- {
- public:
- // ctor
- bounding_box();
- // public functions
- void encompass(const position &);
- // public data
- int blank;
- position ll;
- position ur;
- };
- bounding_box::bounding_box()
- : blank(1)
- {
- }
- void
- bounding_box::encompass(const position &pos)
- {
- if (blank)
- {
- ll = pos;
- ur = pos;
- blank = 0;
- }
- else
- {
- if (pos.x < ll.x)
- ll.x = pos.x;
- if (pos.y < ll.y)
- ll.y = pos.y;
- if (pos.x > ur.x)
- ur.x = pos.x;
- if (pos.y > ur.y)
- ur.y = pos.y;
- }
- }
- void
- object::update_bounding_box(bounding_box *)
- {
- }
- position
- object::origin()
- {
- return position(0.0,0.0);
- }
- position
- object::north()
- {
- return origin();
- }
- position
- object::south()
- {
- return origin();
- }
- position
- object::east()
- {
- return origin();
- }
- position
- object::west()
- {
- return origin();
- }
- position
- object::north_east()
- {
- return origin();
- }
- position
- object::north_west()
- {
- return origin();
- }
- position
- object::south_east()
- {
- return origin();
- }
- position
- object::south_west()
- {
- return origin();
- }
- position
- object::start()
- {
- return origin();
- }
- position
- object::end()
- {
- return origin();
- }
- position
- object::center()
- {
- return origin();
- }
- double
- object::width()
- {
- return 0.0;
- }
- double
- object::radius()
- {
- return 0.0;
- }
- double
- object::height()
- {
- return 0.0;
- }
- place *
- object::find_label(const char *)
- {
- return 0;
- }
- //////////////////////////////////////////////////////////////////////
- // Derived OBJECT classes, declared in object.h
- //////////////////////////////////////////////////////////////////////
- segment::segment(const position &a, int n, segment *p)
- : is_absolute(n), pos(a), next(p)
- {
- }
- text_item::text_item(char *t, const char *fn, int ln)
- : next(0), text(t), filename(fn), lineno(ln)
- {
- adj.h = CENTER_ADJUST;
- adj.v = NONE_ADJUST;
- }
- text_item::~text_item()
- {
- a_delete text;
- }
- object_spec::object_spec(object_type t) : type(t)
- {
- flags = 0;
- tbl = 0;
- segment_list = 0;
- segment_width = segment_height = 0.0;
- segment_is_absolute = 0;
- text = 0;
- with = 0;
- dir = RIGHT_DIRECTION;
- }
- object_spec::~object_spec()
- {
- delete tbl;
- while (segment_list != 0)
- {
- segment *tem = segment_list;
- segment_list = segment_list->next;
- delete tem;
- }
- object *p = oblist.head;
- while (p != 0)
- {
- object *tem = p;
- p = p->next;
- delete tem;
- }
- while (text != 0)
- {
- text_item *tem = text;
- text = text->next;
- delete tem;
- }
- delete with;
- }
- class command_object : public object
- {
- public:
- // ctor, dtor
- command_object(char *, const char *, int);
- ~command_object();
- // public functions
- object_type type() { return OTHER_OBJECT; }
- void print();
- private:
- char *s;
- const char *filename;
- int lineno;
- };
- command_object::command_object(char *p, const char *fn, int ln)
- : s(p), filename(fn), lineno(ln)
- {
- }
- command_object::~command_object()
- {
- a_delete s;
- }
- void command_object::print()
- {
- out->command(s, filename, lineno);
- }
- object *make_command_object(char *s, const char *fn, int ln)
- {
- return new command_object(s, fn, ln);
- }
- class mark_object : public object
- {
- public:
- mark_object();
- object_type type();
- };
- object *
- make_mark_object()
- {
- return new mark_object();
- }
- mark_object::mark_object()
- {
- }
- object_type
- mark_object::type()
- {
- return MARK_OBJECT;
- }
- object_list::object_list() : head(0), tail(0)
- {
- }
- void object_list::append(object *obj)
- {
- if (tail == 0)
- {
- obj->next = obj->prev = 0;
- head = tail = obj;
- }
- else
- {
- obj->prev = tail;
- obj->next = 0;
- tail->next = obj;
- tail = obj;
- }
- }
- void
- object_list::wrap_up_block(object_list *ol)
- {
- object *p;
- for (p = tail; p && p->type() != MARK_OBJECT; p = p->prev)
- ;
- assert(p != 0);
- ol->head = p->next;
- if (ol->head)
- {
- ol->tail = tail;
- ol->head->prev = 0;
- }
- else
- ol->tail = 0;
- tail = p->prev;
- if (tail)
- tail->next = 0;
- else
- head = 0;
- delete p;
- }
- text_piece::text_piece()
- : text(0), filename(0), lineno(-1)
- {
- adj.h = CENTER_ADJUST;
- adj.v = NONE_ADJUST;
- }
- text_piece::~text_piece()
- {
- a_delete text;
- }
- class graphic_object : public object
- {
- public:
- // ctor, dtor
- graphic_object();
- ~graphic_object();
- // public functions
- object_type type() = 0;
- void print_text();
- void add_text(text_item *, int);
- void set_dotted(double);
- void set_dashed(double);
- void set_thickness(double);
- void set_invisible();
- virtual void set_fill(double);
- protected:
- line_type lt;
- private:
- int ntext;
- text_piece *text;
- int aligned;
- };
- graphic_object::graphic_object() : ntext(0), text(0), aligned(0)
- {
- }
- void
- graphic_object::set_dotted(double wid)
- {
- lt.type = line_type::dotted;
- lt.dash_width = wid;
- }
- void
- graphic_object::set_dashed(double wid)
- {
- lt.type = line_type::dashed;
- lt.dash_width = wid;
- }
- void
- graphic_object::set_thickness(double th)
- {
- lt.thickness = th;
- }
- void
- graphic_object::set_fill(double)
- {
- }
- void
- graphic_object::set_invisible()
- {
- lt.type = line_type::invisible;
- }
- void
- graphic_object::add_text(text_item *t, int a)
- {
- aligned = a;
- int len = 0;
- text_item *p;
- for (p = t; p; p = p->next)
- len++;
- if (len == 0)
- text = 0;
- else
- {
- text = new text_piece[len];
- for (p = t, len = 0; p; p = p->next, len++)
- {
- text[len].text = p->text;
- p->text = 0;
- text[len].adj = p->adj;
- text[len].filename = p->filename;
- text[len].lineno = p->lineno;
- }
- }
- ntext = len;
- }
- void
- graphic_object::print_text()
- {
- double angle = 0.0;
- if (aligned)
- {
- position d(end() - start());
- if (d.x != 0.0 || d.y != 0.0)
- angle = atan2(d.y, d.x);
- }
- if (text != 0)
- out->text(center(), text, ntext, angle);
- }
- graphic_object::~graphic_object()
- {
- if (text)
- ad_delete(ntext) text;
- }
- class rectangle_object : public graphic_object
- {
- public:
- rectangle_object(const position &);
- double width() { return dim.x; }
- double height() { return dim.y; }
- position origin() { return cent; }
- position center() { return cent; }
- position north() { return position(cent.x, cent.y + dim.y/2.0); }
- position south() { return position(cent.x, cent.y - dim.y/2.0); }
- position east() { return position(cent.x + dim.x/2.0, cent.y); }
- position west() { return position(cent.x - dim.x/2.0, cent.y); }
- position north_east() { return position(cent.x + dim.x/2.0, cent.y + dim.y/2.0); }
- position north_west() { return position(cent.x - dim.x/2.0, cent.y + dim.y/2.0); }
- position south_east() { return position(cent.x + dim.x/2.0, cent.y - dim.y/2.0); }
- position south_west() { return position(cent.x - dim.x/2.0, cent.y - dim.y/2.0); }
- object_type type() = 0;
- void update_bounding_box(bounding_box *);
- void move_by(const position &);
- protected:
- position cent;
- position dim;
- };
- rectangle_object::rectangle_object(const position &d)
- : dim(d)
- {
- }
- void
- rectangle_object::update_bounding_box(bounding_box *p)
- {
- p->encompass(cent - dim/2.0);
- p->encompass(cent + dim/2.0);
- }
- void
- rectangle_object::move_by(const position &a)
- {
- cent += a;
- }
- class closed_object : public rectangle_object
- {
- public:
- closed_object(const position &);
- object_type type() = 0;
- void set_fill(double);
- protected:
- double fill; // < 0 if not filled
- };
- closed_object::closed_object(const position &pos)
- : rectangle_object(pos), fill(-1.0)
- {
- }
- void
- closed_object::set_fill(double f)
- {
- assert(f >= 0.0);
- fill = f;
- }
- class box_object : public closed_object
- {
- public:
- box_object(const position &, double);
- object_type type() { return BOX_OBJECT; }
- void print();
- position north_east();
- position north_west();
- position south_east();
- position south_west();
- private:
- double xrad;
- double yrad;
- };
- box_object::box_object(const position &pos, double r)
- : closed_object(pos), xrad(dim.x > 0 ? r : -r), yrad(dim.y > 0 ? r : -r)
- {
- }
- const double CHOP_FACTOR = 1.0 - 1.0/M_SQRT2;
- position
- box_object::north_east()
- {
- return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad,
- cent.y + dim.y/2.0 - CHOP_FACTOR*yrad);
- }
- position
- box_object::north_west()
- {
- return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad,
- cent.y + dim.y/2.0 - CHOP_FACTOR*yrad);
- }
- position
- box_object::south_east()
- {
- return position(cent.x + dim.x/2.0 - CHOP_FACTOR*xrad,
- cent.y - dim.y/2.0 + CHOP_FACTOR*yrad);
- }
- position
- box_object::south_west()
- {
- return position(cent.x - dim.x/2.0 + CHOP_FACTOR*xrad,
- cent.y - dim.y/2.0 + CHOP_FACTOR*yrad);
- }
- void
- box_object::print()
- {
- if (lt.type == line_type::invisible && fill < 0.0)
- return;
- if (xrad == 0.0)
- {
- distance dim2 = dim/2.0;
- position vec[4];
- vec[0] = cent + position(dim2.x, -dim2.y);
- vec[1] = cent + position(dim2.x, dim2.y);
- vec[2] = cent + position(-dim2.x, dim2.y);
- vec[3] = cent + position(-dim2.x, -dim2.y);
- out->polygon(vec, 4, lt, fill);
- }
- else
- {
- distance abs_dim(fabs(dim.x), fabs(dim.y));
- out->rounded_box(cent, abs_dim, fabs(xrad), lt, fill);
- }
- }
- graphic_object *
- object_spec::make_box(position *curpos, direction *dirp)
- {
- static double last_box_height;
- static double last_box_width;
- static double last_box_radius;
- static int have_last_box = 0;
- if (!(flags & HAS_HEIGHT))
- {
- if ((flags & IS_SAME) && have_last_box)
- height = last_box_height;
- else
- lookup_variable("boxht", &height);
- }
- if (!(flags & HAS_WIDTH))
- {
- if ((flags & IS_SAME) && have_last_box)
- width = last_box_width;
- else
- lookup_variable("boxwid", &width);
- }
- if (!(flags & HAS_RADIUS))
- {
- if ((flags & IS_SAME) && have_last_box)
- radius = last_box_radius;
- else
- lookup_variable("boxrad", &radius);
- }
- last_box_width = width;
- last_box_height = height;
- last_box_radius = radius;
- have_last_box = 1;
- radius = fabs(radius);
- if (radius*2.0 > fabs(width))
- radius = fabs(width/2.0);
- if (radius*2.0 > fabs(height))
- radius = fabs(height/2.0);
- box_object *p = new box_object(position(width, height), radius);
- if (!position_rectangle(p, curpos, dirp))
- {
- delete p;
- p = 0;
- }
- return p;
- }
- // return non-zero for success
- int
- object_spec::position_rectangle(rectangle_object *p,
- position *curpos, direction *dirp)
- {
- position pos;
- dir = *dirp; // ignore any direction in attribute list
- position motion;
- switch (dir)
- {
- case UP_DIRECTION:
- motion.y = p->height()/2.0;
- break;
- case DOWN_DIRECTION:
- motion.y = -p->height()/2.0;
- break;
- case LEFT_DIRECTION:
- motion.x = -p->width()/2.0;
- break;
- case RIGHT_DIRECTION:
- motion.x = p->width()/2.0;
- break;
- default:
- assert(0);
- }
- if (flags & HAS_AT)
- {
- pos = at;
- if (flags & HAS_WITH)
- {
- place offset;
- place here;
- here.obj = p;
- if (!with->follow(here, &offset))
- return 0;
- pos -= offset;
- }
- }
- else
- {
- pos = *curpos;
- pos += motion;
- }
- p->move_by(pos);
- pos += motion;
- *curpos = pos;
- return 1;
- }
- class block_object : public rectangle_object
- {
- public:
- // ctor, dtor
- block_object(const position &, const object_list &ol, PTABLE(place) *t);
- ~block_object();
- // public functions
- place *find_label(const char *);
- object_type type();
- void move_by(const position &);
- void print();
- private:
- object_list oblist;
- PTABLE(place) *tbl;
- };
- block_object::block_object(const position &d, const object_list &ol,
- PTABLE(place) *t)
- : oblist(ol), tbl(t), rectangle_object(d)
- {
- }
- block_object::~block_object()
- {
- delete tbl;
- object *p = oblist.head;
- while (p != 0)
- {
- object *tem = p;
- p = p->next;
- delete tem;
- }
- }
- void
- block_object::print()
- {
- out->begin_block(south_west(), north_east());
- print_object_list(oblist.head);
- out->end_block();
- }
- static void
- adjust_objectless_places(PTABLE(place) *tbl, const position &a)
- {
- // Adjust all the labels that aren't attached to objects.
- PTABLE_ITERATOR(place) iter(tbl);
- const char *key;
- place *pl;
- while (iter.next(&key, &pl))
- if (key && csupper(key[0]) && pl->obj == 0)
- {
- pl->x += a.x;
- pl->y += a.y;
- }
- }
- void
- block_object::move_by(const position &a)
- {
- cent += a;
- for (object *p = oblist.head; p; p = p->next)
- p->move_by(a);
- adjust_objectless_places(tbl, a);
- }
- place *
- block_object::find_label(const char *name)
- {
- return tbl->lookup(name);
- }
- object_type
- block_object::type()
- {
- return BLOCK_OBJECT;
- }
- graphic_object *
- object_spec::make_block(position *curpos, direction *dirp)
- {
- bounding_box bb;
- for (object *p = oblist.head; p; p = p->next)
- p->update_bounding_box(&bb);
- position dim;
- if (!bb.blank)
- {
- position m = -(bb.ll + bb.ur)/2.0;
- for (object *p = oblist.head; p; p = p->next)
- p->move_by(m);
- adjust_objectless_places(tbl, m);
- dim = bb.ur - bb.ll;
- }
- if (flags & HAS_WIDTH)
- dim.x = width;
- if (flags & HAS_HEIGHT)
- dim.y = height;
- block_object *block = new block_object(dim, oblist, tbl);
- if (!position_rectangle(block, curpos, dirp))
- {
- delete block;
- block = 0;
- }
- tbl = 0;
- oblist.head = oblist.tail = 0;
- return block;
- }
- class text_object : public rectangle_object
- {
- public:
- text_object(const position &);
- object_type type() { return TEXT_OBJECT; }
- };
- text_object::text_object(const position &d)
- : rectangle_object(d)
- {
- }
- graphic_object *
- object_spec::make_text(position *curpos, direction *dirp)
- {
- if (!(flags & HAS_HEIGHT))
- {
- lookup_variable("textht", &height);
- int nitems = 0;
- for (text_item *t = text; t; t = t->next)
- nitems++;
- height *= nitems;
- }
- if (!(flags & HAS_WIDTH))
- lookup_variable("textwid", &width);
- text_object *p = new text_object(position(width, height));
- if (!position_rectangle(p, curpos, dirp))
- {
- delete p;
- p = 0;
- }
- return p;
- }
- class ellipse_object : public closed_object
- {
- public:
- ellipse_object(const position &);
- position north_east() { return position(cent.x + dim.x/(M_SQRT2*2.0),
- cent.y + dim.y/(M_SQRT2*2.0)); }
- position north_west() { return position(cent.x - dim.x/(M_SQRT2*2.0),
- cent.y + dim.y/(M_SQRT2*2.0)); }
- position south_east() { return position(cent.x + dim.x/(M_SQRT2*2.0),
- cent.y - dim.y/(M_SQRT2*2.0)); }
- position south_west() { return position(cent.x - dim.x/(M_SQRT2*2.0),
- cent.y - dim.y/(M_SQRT2*2.0)); }
- double radius() { return dim.x/2.0; }
- object_type type() { return ELLIPSE_OBJECT; }
- void print();
- };
- ellipse_object::ellipse_object(const position &d)
- : closed_object(d)
- {
- }
- void ellipse_object::print()
- {
- if (lt.type == line_type::invisible && fill < 0.0)
- return;
- out->ellipse(cent, dim, lt, fill);
- }
- graphic_object *
- object_spec::make_ellipse(position *curpos, direction *dirp)
- {
- static double last_ellipse_height;
- static double last_ellipse_width;
- static int have_last_ellipse = 0;
- if (!(flags & HAS_HEIGHT))
- {
- if ((flags & IS_SAME) && have_last_ellipse)
- height = last_ellipse_height;
- else
- lookup_variable("ellipseht", &height);
- }
- if (!(flags & HAS_WIDTH))
- {
- if ((flags & IS_SAME) && have_last_ellipse)
- width = last_ellipse_width;
- else
- lookup_variable("ellipsewid", &width);
- }
- last_ellipse_width = width;
- last_ellipse_height = height;
- have_last_ellipse = 1;
- ellipse_object *p = new ellipse_object(position(width, height));
- if (!position_rectangle(p, curpos, dirp))
- {
- delete p;
- return 0;
- }
- return p;
- }
- class circle_object : public ellipse_object
- {
- public:
- // ctor
- circle_object(double);
- // public functions
- object_type type() { return CIRCLE_OBJECT; }
- void print();
- };
- circle_object::circle_object(double diam)
- : ellipse_object(position(diam, diam))
- {
- }
- void
- circle_object::print()
- {
- if (lt.type == line_type::invisible && fill < 0.0)
- return;
- out->circle(cent, dim.x/2.0, lt, fill);
- }
- graphic_object *
- object_spec::make_circle(position *curpos, direction *dirp)
- {
- static double last_circle_radius;
- static int have_last_circle = 0;
- if (!(flags & HAS_RADIUS))
- {
- if ((flags & IS_SAME) && have_last_circle)
- radius = last_circle_radius;
- else
- lookup_variable("circlerad", &radius);
- }
- last_circle_radius = radius;
- have_last_circle = 1;
- circle_object *p = new circle_object(radius*2.0);
- if (!position_rectangle(p, curpos, dirp))
- {
- delete p;
- return 0;
- }
- return p;
- }
- class move_object : public graphic_object
- {
- position strt;
- position en;
- public:
- move_object(const position &s, const position &e);
- position origin() { return en; }
- object_type type() { return MOVE_OBJECT; }
- void update_bounding_box(bounding_box *);
- void move_by(const position &);
- };
- move_object::move_object(const position &s, const position &e)
- : strt(s), en(e)
- {
- }
- void
- move_object::update_bounding_box(bounding_box *p)
- {
- p->encompass(strt);
- p->encompass(en);
- }
- void
- move_object::move_by(const position &a)
- {
- strt += a;
- en += a;
- }
- graphic_object *
- object_spec::make_move(position *curpos, direction *dirp)
- {
- static position last_move;
- static int have_last_move = 0;
- *dirp = dir;
- // No need to look at at since `at' attribute sets `from' attribute.
- position startpos = (flags & HAS_FROM) ? from : *curpos;
- if (!(flags & HAS_SEGMENT))
- {
- if ((flags && IS_SAME) && have_last_move)
- segment_pos = last_move;
- else
- {
- switch (dir)
- {
- case UP_DIRECTION:
- segment_pos.y = segment_height;
- break;
- case DOWN_DIRECTION:
- segment_pos.y = -segment_height;
- break;
- case LEFT_DIRECTION:
- segment_pos.x = -segment_width;
- break;
- case RIGHT_DIRECTION:
- segment_pos.x = segment_width;
- break;
- default:
- assert(0);
- }
- }
- }
- segment_list = new segment(segment_pos, segment_is_absolute, segment_list);
- // Reverse the segment_list so that it's in forward order.
- segment *old = segment_list;
- segment_list = 0;
- while (old != 0)
- {
- segment *tem = old->next;
- old->next = segment_list;
- segment_list = old;
- old = tem;
- }
- // Compute the end position.
- position endpos = startpos;
- for (segment *s = segment_list; s; s = s->next)
- if (s->is_absolute)
- endpos = s->pos;
- else
- endpos += s->pos;
- have_last_move = 1;
- last_move = endpos - startpos;
- move_object *p = new move_object(startpos, endpos);
- *curpos = endpos;
- return p;
- }
- class linear_object : public graphic_object
- {
- public:
- // ctor
- linear_object(const position &s, const position &e);
- // public functions
- position start() { return strt; }
- position end() { return en; }
- void move_by(const position &);
- void update_bounding_box(bounding_box *) = 0;
- object_type type() = 0;
- void add_arrows(int at_start, int at_end, const arrow_head_type &);
- protected:
- char arrow_at_start;
- char arrow_at_end;
- arrow_head_type aht;
- position strt;
- position en;
- };
- class line_object : public linear_object
- {
- public:
- // ctor, dtor
- line_object(const position &s, const position &e, position *, int);
- ~line_object();
- // public functions
- position origin() { return strt; }
- position center() { return (strt + en)/2.0; }
- position north() { return (en.y - strt.y) > 0 ? en : strt; }
- position south() { return (en.y - strt.y) < 0 ? en : strt; }
- position east() { return (en.x - strt.x) > 0 ? en : strt; }
- position west() { return (en.x - strt.x) < 0 ? en : strt; }
- object_type type() { return LINE_OBJECT; }
- void update_bounding_box(bounding_box *);
- void print();
- void move_by(const position &);
- protected:
- position *v;
- int n;
- };
- class arrow_object : public line_object
- {
- public:
- arrow_object(const position &, const position &, position *, int);
- object_type type() { return ARROW_OBJECT; }
- };
- class spline_object : public line_object
- {
- public:
- spline_object(const position &, const position &, position *, int);
- object_type type() { return SPLINE_OBJECT; }
- void print();
- void update_bounding_box(bounding_box *);
- };
- linear_object::linear_object(const position &s, const position &e)
- : arrow_at_start(0), arrow_at_end(0), strt(s), en(e)
- {
- }
- void
- linear_object::move_by(const position &a)
- {
- strt += a;
- en += a;
- }
- void
- linear_object::add_arrows(int at_start, int at_end,
- const arrow_head_type &a)
- {
- arrow_at_start = at_start;
- arrow_at_end = at_end;
- aht = a;
- }
- line_object::line_object(const position &s, const position &e,
- position *p, int i)
- : v(p), n(i), linear_object(s, e)
- {
- }
- void
- line_object::print()
- {
- if (lt.type == line_type::invisible)
- return;
- out->line(strt, v, n, lt);
- if (arrow_at_start)
- draw_arrow(strt, strt-v[0], aht, lt);
- if (arrow_at_end)
- draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);
- }
- void
- line_object::update_bounding_box(bounding_box *p)
- {
- p->encompass(strt);
- for (int i = 0; i < n; i++)
- p->encompass(v[i]);
- }
- void
- line_object::move_by(const position &pos)
- {
- linear_object::move_by(pos);
- for (int i = 0; i < n; i++)
- v[i] += pos;
- }
- void
- spline_object::update_bounding_box(bounding_box *p)
- {
- p->encompass(strt);
- p->encompass(en);
- /*
- If
- p1 = q1/2 + q2/2
- p2 = q1/6 + q2*5/6
- p3 = q2*5/6 + q3/6
- p4 = q2/2 + q3/2
- [ the points for the Bezier cubic ]
- and
- t = .5
- then
- (1-t)^3*p1 + 3*t*(t - 1)^2*p2 + 3*t^2*(1-t)*p3 + t^3*p4
- [ the equation for the Bezier cubic ]
- = .125*q1 + .75*q2 + .125*q3
- */
-
- for (int i = 1; i < n; i++)
- p->encompass((i == 1 ? strt : v[i-2])*.125 + v[i-1]*.75 + v[i]*.125);
- }
- arrow_object::arrow_object(const position &s, const position &e,
- position *p, int i)
- : line_object(s, e, p, i)
- {
- }
- spline_object::spline_object(const position &s, const position &e,
- position *p, int i)
- : line_object(s, e, p, i)
- {
- }
- void
- spline_object::print()
- {
- if (lt.type == line_type::invisible)
- return;
- out->spline(strt, v, n, lt);
- if (arrow_at_start)
- draw_arrow(strt, strt-v[0], aht, lt);
- if (arrow_at_end)
- draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);
- }
- line_object::~line_object()
- {
- a_delete v;
- }
- linear_object *
- object_spec::make_line(position *curpos, direction *dirp)
- {
- static position last_line;
- static int have_last_line = 0;
- *dirp = dir;
- // No need to look at at since `at' attribute sets `from' attribute.
- position startpos = (flags & HAS_FROM) ? from : *curpos;
- if (!(flags & HAS_SEGMENT))
- {
- if ((flags & IS_SAME) && (type == LINE_OBJECT || type == ARROW_OBJECT)
- && have_last_line)
- segment_pos = last_line;
- else
- switch (dir)
- {
- case UP_DIRECTION:
- segment_pos.y = segment_height;
- break;
- case DOWN_DIRECTION:
- segment_pos.y = -segment_height;
- break;
- case LEFT_DIRECTION:
- segment_pos.x = -segment_width;
- break;
- case RIGHT_DIRECTION:
- segment_pos.x = segment_width;
- break;
- default:
- assert(0);
- }
- }
- segment_list = new segment(segment_pos, segment_is_absolute, segment_list);
- // reverse the segment_list so that it's in forward order
- segment *old = segment_list;
- segment_list = 0;
- while (old != 0)
- {
- segment *tem = old->next;
- old->next = segment_list;
- segment_list = old;
- old = tem;
- }
- // Absolutise all movements
- position endpos = startpos;
- int nsegments = 0;
- segment *s;
- for (s = segment_list; s; s = s->next, nsegments++)
- if (s->is_absolute)
- endpos = s->pos;
- else
- {
- endpos += s->pos;
- s->pos = endpos;
- s->is_absolute = 1; // to avoid confusion
- }
- // handle chop
- line_object *p = 0;
- position *v = new position[nsegments];
- int i = 0;
- for (s = segment_list; s; s = s->next, i++)
- v[i] = s->pos;
- if (flags & IS_DEFAULT_CHOPPED)
- {
- lookup_variable("circlerad", &start_chop);
- end_chop = start_chop;
- flags |= IS_CHOPPED;
- }
- if (flags & IS_CHOPPED)
- {
- position start_chop_vec, end_chop_vec;
- if (start_chop != 0.0)
- {
- start_chop_vec = v[0] - startpos;
- start_chop_vec *= start_chop / hypot(start_chop_vec);
- }
- if (end_chop != 0.0)
- {
- end_chop_vec = (v[nsegments - 1]
- - (nsegments > 1 ? v[nsegments - 2] : startpos));
- end_chop_vec *= end_chop / hypot(end_chop_vec);
- }
- startpos += start_chop_vec;
- v[nsegments - 1] -= end_chop_vec;
- endpos -= end_chop_vec;
- }
- switch (type)
- {
- case SPLINE_OBJECT:
- p = new spline_object(startpos, endpos, v, nsegments);
- break;
- case ARROW_OBJECT:
- p = new arrow_object(startpos, endpos, v, nsegments);
- break;
- case LINE_OBJECT:
- p = new line_object(startpos, endpos, v, nsegments);
- break;
- default:
- assert(0);
- }
- have_last_line = 1;
- last_line = endpos - startpos;
- *curpos = endpos;
- return p;
- }
- class arc_object : public linear_object
- {
- public:
- arc_object(int, const position &, const position &, const position &);
- position origin() { return cent; }
- position center() { return cent; }
- double radius() { return rad; }
- position north();
- position south();
- position east();
- position west();
- position north_east();
- position north_west();
- position south_east();
- position south_west();
- void update_bounding_box(bounding_box *);
- object_type type() { return ARC_OBJECT; }
- void print();
- void move_by(const position &pos);
- private:
- int clockwise;
- position cent;
- double rad;
- };
- arc_object::arc_object(int cw, const position &s, const position &e,
- const position &c)
- : linear_object(s, e), clockwise(cw), cent(c)
- {
- rad = hypot(c - s);
- }
- void
- arc_object::move_by(const position &pos)
- {
- linear_object::move_by(pos);
- cent += pos;
- }
- // we get arc corners from the corresponding circle
- position
- arc_object::north()
- {
- position result(cent);
- result.y += rad;
- return result;
- }
- position
- arc_object::south()
- {
- position result(cent);
- result.y -= rad;
- return result;
- }
- position
- arc_object::east()
- {
- position result(cent);
- result.x += rad;
- return result;
- }
- position
- arc_object::west()
- {
- position result(cent);
- result.x -= rad;
- return result;
- }
- position
- arc_object::north_east()
- {
- position result(cent);
- result.x += rad/M_SQRT2;
- result.y += rad/M_SQRT2;
- return result;
- }
- position
- arc_object::north_west()
- {
- position result(cent);
- result.x -= rad/M_SQRT2;
- result.y += rad/M_SQRT2;
- return result;
- }
- position
- arc_object::south_east()
- {
- position result(cent);
- result.x += rad/M_SQRT2;
- result.y -= rad/M_SQRT2;
- return result;
- }
- position
- arc_object::south_west()
- {
- position result(cent);
- result.x -= rad/M_SQRT2;
- result.y -= rad/M_SQRT2;
- return result;
- }
- void
- arc_object::print()
- {
- if (lt.type == line_type::invisible)
- return;
- #ifndef PIC2PLOT
- if (clockwise)
- out->arc(en, cent, strt, lt);
- else
- out->arc(strt, cent, en, lt);
- #else
- out->arc(strt, cent, en, lt);
- #endif
- if (arrow_at_start)
- {
- position c = cent - strt;
- draw_arrow(strt,
- (clockwise ? position(c.y, -c.x) : position(-c.y, c.x)),
- aht, lt);
- }
- if (arrow_at_end)
- {
- position e = en - cent;
- draw_arrow(en,
- (clockwise ? position(e.y, -e.x) : position(-e.y, e.x)),
- aht, lt);
- }
- }
- inline double
- max(double a, double b)
- {
- return a > b ? a : b;
- }
- void
- arc_object::update_bounding_box(bounding_box *p)
- {
- p->encompass(strt);
- p->encompass(en);
- position start_offset = strt - cent;
- if (start_offset.x == 0.0 && start_offset.y == 0.0)
- return;
- position end_offset = en - cent;
- if (end_offset.x == 0.0 && end_offset.y == 0.0)
- return;
- double start_quad = atan2(start_offset.y, start_offset.x)/(M_PI/2.0);
- double end_quad = atan2(end_offset.y, end_offset.x)/(M_PI/2.0);
- if (clockwise)
- {
- double temp = start_quad;
- start_quad = end_quad;
- end_quad = temp;
- }
- if (start_quad < 0.0)
- start_quad += 4.0;
- while (end_quad <= start_quad)
- end_quad += 4.0;
- double radius = max(hypot(start_offset), hypot(end_offset));
- for (int q = int(start_quad) + 1; q < end_quad; q++)
- {
- position offset;
- switch (q % 4)
- {
- case 0:
- offset.x = radius;
- break;
- case 1:
- offset.y = radius;
- break;
- case 2:
- offset.x = -radius;
- break;
- case 3:
- offset.y = -radius;
- break;
- }
- p->encompass(cent + offset);
- }
- }
- // We ignore the with attribute. The at attribute always refers to the center.
- linear_object *
- object_spec::make_arc(position *curpos, direction *dirp)
- {
- *dirp = dir;
- int cw = (flags & IS_CLOCKWISE) != 0;
- // compute the start
- position startpos;
- if (flags & HAS_FROM)
- startpos = from;
- else
- startpos = *curpos;
- if (!(flags & HAS_RADIUS))
- lookup_variable("arcrad", &radius);
- // compute the end
- position endpos;
- if (flags & HAS_TO)
- endpos = to;
- else
- {
- position m(radius, radius);
- // Adjust the signs.
- if (cw)
- {
- if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION)
- m.x = -m.x;
- if (dir == DOWN_DIRECTION || dir == RIGHT_DIRECTION)
- m.y = -m.y;
- *dirp = direction((dir + 3) % 4);
- }
- else
- {
- if (dir == UP_DIRECTION || dir == LEFT_DIRECTION)
- m.x = -m.x;
- if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION)
- m.y = -m.y;
- *dirp = direction((dir + 1) % 4);
- }
- endpos = startpos + m;
- }
- // compute the center
- position centerpos;
- if (flags & HAS_AT)
- centerpos = at;
- else if (startpos == endpos)
- centerpos = startpos;
- else
- {
- position h = (endpos - startpos)/2.0;
- double d = hypot(h);
- if (radius <= 0)
- radius = .25;
- // make the radius big enough
- while (radius < d)
- radius *= 2.0;
- double alpha = acos(d/radius);
- double theta = atan2(h.y, h.x);
- if (cw)
- theta -= alpha;
- else
- theta += alpha;
- centerpos = position(cos(theta), sin(theta))*radius + startpos;
- }
- arc_object *p = new arc_object(cw, startpos, endpos, centerpos);
- *curpos = endpos;
- return p;
- }
- graphic_object *
- object_spec::make_linear(position *curpos, direction *dirp)
- {
- linear_object *obj;
- if (type == ARC_OBJECT)
- obj = make_arc(curpos, dirp);
- else
- obj = make_line(curpos, dirp);
- if (type == ARROW_OBJECT
- && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD)) == 0)
- flags |= HAS_RIGHT_ARROW_HEAD;
- if (obj && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD)))
- {
- arrow_head_type a;
- int at_start = (flags & HAS_LEFT_ARROW_HEAD) != 0;
- int at_end = (flags & HAS_RIGHT_ARROW_HEAD) != 0;
- if (flags & HAS_HEIGHT)
- a.height = height;
- else
- lookup_variable("arrowht", &a.height);
- if (flags & HAS_WIDTH)
- a.width = width;
- else
- lookup_variable("arrowwid", &a.width);
- double solid;
- lookup_variable("arrowhead", &solid);
- a.solid = solid != 0.0;
- obj->add_arrows(at_start, at_end, a);
- }
- return obj;
- }
- object *
- object_spec::make_object(position *curpos, direction *dirp)
- {
- graphic_object *obj = 0;
- switch (type)
- {
- case BLOCK_OBJECT:
- obj = make_block(curpos, dirp);
- break;
- case BOX_OBJECT:
- obj = make_box(curpos, dirp);
- break;
- case TEXT_OBJECT:
- obj = make_text(curpos, dirp);
- break;
- case ELLIPSE_OBJECT:
- obj = make_ellipse(curpos, dirp);
- break;
- case CIRCLE_OBJECT:
- obj = make_circle(curpos, dirp);
- break;
- case MOVE_OBJECT:
- obj = make_move(curpos, dirp);
- break;
- case ARC_OBJECT:
- case LINE_OBJECT:
- case SPLINE_OBJECT:
- case ARROW_OBJECT:
- obj = make_linear(curpos, dirp);
- break;
- case MARK_OBJECT:
- case OTHER_OBJECT:
- default:
- assert(0);
- break;
- }
- if (obj)
- {
- if (flags & IS_INVISIBLE)
- obj->set_invisible();
- if (text != 0)
- obj->add_text(text, (flags & IS_ALIGNED) != 0);
- if (flags & IS_DOTTED)
- obj->set_dotted(dash_width);
- else if (flags & IS_DASHED)
- obj->set_dashed(dash_width);
- double th;
- if (flags & HAS_THICKNESS)
- th = thickness;
- else
- lookup_variable("linethick", &th);
- obj->set_thickness(th);
- if (flags & (IS_DEFAULT_FILLED|IS_FILLED))
- {
- if (flags & IS_DEFAULT_FILLED)
- lookup_variable("fillval", &fill);
- if (fill < 0.0)
- error("bad fill value %1", fill);
- else
- obj->set_fill(fill);
- }
- }
- return obj;
- }
- class string_list
- {
- public:
- // ctor, dtor
- string_list(char *);
- ~string_list();
- // public data
- string_list *next;
- char *str;
- };
- string_list::string_list(char *s)
- : next(0), str(s)
- {
- }
- string_list::~string_list()
- {
- a_delete str;
- }
- //////////////////////////////////////////////////////////////////////
- // The PATH class, declared in object.h
- //////////////////////////////////////////////////////////////////////
- // A path is used to hold the argument to the `with' attribute. For example,
- // `.nw' or `.A.s' or `.A'. The major operation on a path is to take a
- // place and follow the path through the place to place within the place.
- // Note that `.A.B.C.sw' will work.
- path::path(corner c)
- : crn(c), label_list(0), ypath(0)
- {
- }
- path::path(char *l, corner c)
- : crn(c), ypath(0)
- {
- label_list = new string_list(l);
- }
- path::~path()
- {
- while (label_list)
- {
- string_list *tem = label_list;
- label_list = label_list->next;
- delete tem;
- }
- delete ypath;
- }
- void
- path::append(corner c)
- {
- assert(crn == 0);
- crn = c;
- }
- void
- path::append(char *s)
- {
- string_list **p;
- for (p = &label_list; *p; p = &(*p)->next)
- ;
- *p = new string_list(s);
- }
- void
- path::set_ypath(path *p)
- {
- ypath = p;
- }
- // return non-zero for success
- int
- path::follow(const place &pl, place *result) const
- {
- const place *p = &pl;
- for (string_list *lb = label_list; lb; lb = lb->next)
- if (p->obj == 0 || (p = p->obj->find_label(lb->str)) == 0)
- {
- lex_error("object does not contain a place `%1'", lb->str);
- return 0;
- }
- if (crn == 0 || p->obj == 0)
- *result = *p;
- else
- {
- position pos = ((p->obj)->*(crn))();
- result->x = pos.x;
- result->y = pos.y;
- result->obj = 0;
- }
- if (ypath)
- {
- place tem;
- if (!ypath->follow(pl, &tem))
- return 0;
- result->y = tem.y;
- if (result->obj != tem.obj)
- result->obj = 0;
- }
- return 1;
- }
- static void
- print_object_list(object *p)
- {
- for (; p; p = p->next)
- {
- p->print();
- p->print_text();
- }
- }
- void
- print_picture(object *obj)
- {
- bounding_box bb;
- double scale;
- for (object *p = obj; p; p = p->next)
- p->update_bounding_box (&bb);
- lookup_variable ("scale", &scale);
- out->start_picture (scale, bb.ll, bb.ur);
- print_object_list (obj);
- out->finish_picture ();
- }
|