123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938 |
- /* 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. */
- // The `plot_output' class, subclassed from the `common_output' class.
- // In this class we invoke GNU libplot operations to draw objects.
- // If the `precision_dashing' flag is set, we draw some types of object
- // (arcs, polygons, circles, rounded boxes) in a special way. The object
- // boundary is drawn as a sequence of line segments (if it's to be
- // "dashed") or a sequence of filled circles (if it's to be "dotted").
- // This is done by invoking e.g. the dashed_arc, dotted_arc, dashed_circle,
- // dotted_circle, and rounded_box operations in the `common_output'
- // superclass.
- // This is the only reason why we subclass from `common_output', rather
- // than directly from `output'.
- #include "pic.h"
- #include "output.h"
- #include "common.h"
- #include "plot.h" // libplot header file
- // Plotter parameter array, set from command line in main.cc
- extern plPlotterParams *plotter_params;
- // size of graphics display in `virtual inches'
- #define DISPLAY_SIZE_IN_INCHES 8.0
- #define POINTS_PER_INCH 72.0
- // color name array in libplot; undocumented but accessible to programmers
- typedef struct
- {
- const char *name;
- unsigned char red;
- unsigned char green;
- unsigned char blue;
- } Colornameinfo;
- extern const Colornameinfo _colornames[];
- // our libplot driver
- class plot_output : public common_output
- {
- public:
- // ctor, dtor
- plot_output();
- ~plot_output();
- // basic interface
- void start_picture (double sc, const position &ll, const position &ur);
- void finish_picture (void);
- // draw objects
- void arc (const position &start, const position ¢, const position &end,
- const line_type <);
- void circle (const position ¢, double rad, const line_type <,
- double fill);
- void ellipse (const position ¢, const distance &dim,
- const line_type <, double fill);
- void line (const position &start, const position *v, int n,
- const line_type <);
- void polygon (const position *v, int n,
- const line_type <, double fill);
- void spline (const position &start, const position *v, int n,
- const line_type <);
- void text (const position ¢er, text_piece *v, int n, double angle);
- void rounded_box (const position ¢, const distance &dim,
- double rad, const line_type <, double fill);
- // attribute-querying function
- int supports_filled_polygons (void);
- private:
- // parameters
- plPlotter *plotter; // pointer to opaque libplot Plotter object
- double default_plotter_line_thickness; // line thickness in virtual points
- int pen_red, pen_green, pen_blue; // 48-bit pen color
- // dynamic variables, keep track of Plotter drawing state
- int plotter_line_type; // one of line_type::solid etc.
- int plotter_fill_fraction; // libplot fill fraction
- double plotter_line_thickness; // in virtual points
- bool plotter_visible_pen; // default is `yes'
- bool plotter_path_in_progress; // need to break?
- // internal functions, modify Plotter drawing state
- void set_line_type_and_thickness (const line_type <);
- void set_fill (double fill);
- void set_pen_visibility (bool visible);
- // invoked by common_output dotting methods
- void dot (const position &pos, const line_type <);
- };
- output *
- make_plot_output()
- {
- return new plot_output;
- }
- plot_output::plot_output()
- {
- if ((plotter = pl_newpl_r (output_format, NULL, stdout, stderr,
- plotter_params)) == NULL)
- {
- fprintf (stderr, "%s: error: could not open plot device\n",
- program_name);
- exit (EXIT_FAILURE);
- }
- }
- plot_output::~plot_output()
- {
- pl_deletepl_r (plotter);
- }
- void
- plot_output::start_picture(double sc, const position &ll,
- const position &ur)
- {
- double xcen, ycen, xmin, xmax, ymin, ymax;
- double scale;
- // open Plotter; record Plotter drawing state defaults
- pl_openpl_r (plotter);
- plotter_line_type = line_type::solid;
- plotter_fill_fraction = 0; // i.e. unfilled
- plotter_visible_pen = true;
- plotter_path_in_progress = false;
- // Compute scale factor via compute_scale() method of output
- // class; see object.cc. .PS line may contain desired width/height
- // in virtual inches; if so, scale to it. If .PS line doesn't contain
- // desired width/height, scale according to the global `scale' variable
- // (normally set at top of pic file. But on no account violate
- // the bounds maxpswid/maxpsht.
- scale = compute_scale(sc, ll, ur);
- /* Initialize map from user space to device space, by specifying
- rectangle in user space that will be mapped to graphics display in
- device space. Possibly choose rectangle so that plot will be
- centered on the display. */
- if (no_centering_flag)
- {
- xmin = 0.0;
- ymin = 0.0;
- }
- else // center
- {
- xcen = 0.5 * (ll.x + ur.x);
- ycen = 0.5 * (ll.y + ur.y);
- xmin = xcen - 0.5 * DISPLAY_SIZE_IN_INCHES * scale;
- ymin = ycen - 0.5 * DISPLAY_SIZE_IN_INCHES * scale;
- }
- xmax = xmin + DISPLAY_SIZE_IN_INCHES * scale;
- ymax = ymin + DISPLAY_SIZE_IN_INCHES * scale;
- pl_fspace_r (plotter, xmin, ymin, xmax, ymax);
- // clear Plotter of objects; initialize font name
- pl_erase_r (plotter);
- if (font_name)
- pl_fontname_r (plotter, font_name);
-
- // set pen/fill color (will modify later only by invoking pl_filltype_r)
- if (pen_color_name)
- pl_colorname_r (plotter, pen_color_name);
- // initialize font size and line thickness from values that can be set on
- // the command line (latter is dynamic, can be altered in pic file)
- font_size *= scale;
- line_width *= scale;
- if (font_size >= 0.0)
- // `font size', as set on command line, is in terms of display width,
- // but libplot, according to our scaling, uses virtual inches; so we
- // convert
- pl_ffontsize_r (plotter, DISPLAY_SIZE_IN_INCHES * font_size);
- else
- // use Plotter default; no need to issue a fontsize() instruction
- {
- }
- if (line_width >= 0.0)
- {
- // `line_width', as set on command line, is in terms of display
- // width, but libplot, according to our scaling, uses virtual inches;
- // pic2plot, uses virtual points both internally and in pic scripts
- pl_flinewidth_r (plotter, DISPLAY_SIZE_IN_INCHES * line_width);
- default_plotter_line_thickness
- = DISPLAY_SIZE_IN_INCHES * POINTS_PER_INCH * line_width;
- }
- else
- // use Plotter default, represented internally by pic2plot as -1;
- // no need to issue a linewidth() instruction
- default_plotter_line_thickness = -1.0;
- /* store initial line thickness as a default, for later use */
- plotter_line_thickness = default_plotter_line_thickness;
- }
- void
- plot_output::finish_picture()
- {
- pl_closepl_r (plotter);
- }
- //////////////////////////////////////////////////////////////////////
- // SET PLOTTER DRAWING ATTRIBUTES
- //////////////////////////////////////////////////////////////////////
- // Manipulate fill color (idempotent, so may not actually do anything,
- // i.e. may not break the path in progress, if any).
- void
- plot_output::set_fill (double fill)
- {
- int fill_fraction;
- if (fill < 0.0)
- fill_fraction = 0; // unfilled
- else
- {
- if (fill > 1.0)
- fill = 1.0;
- /* fill=0.0 is white, fraction=0xffff;
- fill=1.0 is solid color, fraction = 1 */
- fill_fraction = 0xffff - IROUND(0xfffe * fill);
- }
- if (fill_fraction != plotter_fill_fraction)
- {
- // manipulate fill color by setting the fill fraction
- pl_filltype_r (plotter, fill_fraction);
- plotter_fill_fraction = fill_fraction;
- plotter_path_in_progress = false;
- }
- }
- // Set line type (solid/dashed/dotted) and thickness. May not invoke a
- // libplot operation if neither needs to be changed, so may not break the
- // path in progress (if any).
- void
- plot_output::set_line_type_and_thickness (const line_type <)
- {
- switch (lt.type)
- {
- case line_type::solid:
- default:
- if (plotter_line_type != line_type::solid)
- {
- pl_linemod_r (plotter, "solid");
- plotter_line_type = line_type::solid;
- plotter_path_in_progress = false;
- }
- break;
- case line_type::dotted:
- if (plotter_line_type != line_type::dotted)
- {
- double dashbuf[2];
- pl_linemod_r (plotter, "dotted");
- dashbuf[0] = 0.25 * lt.dash_width;
- dashbuf[1] = 0.75 * lt.dash_width;
- pl_flinedash_r (plotter, 2, dashbuf, 0.0);
- plotter_line_type = line_type::dotted;
- plotter_path_in_progress = false;
- }
- break;
- case line_type::dashed:
- if (plotter_line_type != line_type::dashed)
- {
- double dashbuf[2];
- pl_linemod_r (plotter, "shortdashed");
- dashbuf[0] = dashbuf[1] = lt.dash_width;
- pl_flinedash_r (plotter, 2, dashbuf, 0.0);
- plotter_line_type = line_type::dashed;
- plotter_path_in_progress = false;
- }
- break;
- }
- if (lt.thickness != plotter_line_thickness
- &&
- !(lt.thickness < 0.0 && plotter_line_thickness < 0.0))
- // need to change (recall negative thickness means `default')
- {
- if (lt.thickness < 0)
- pl_flinewidth_r (plotter,
- default_plotter_line_thickness / POINTS_PER_INCH);
- else
- pl_flinewidth_r (plotter, lt.thickness / POINTS_PER_INCH);
- plotter_line_thickness = lt.thickness;
- plotter_path_in_progress = false;
- }
- }
- // Set pen visibility (true/false). This is needed for precision dashing
- // around the boundary of any closed object; provided that it is filled, at
- // least. When first drawing the closed object itself, pen visibility
- // needs to be set to `false'.
- void
- plot_output::set_pen_visibility (bool visible)
- {
- if (visible != plotter_visible_pen)
- {
- if (visible)
- pl_pentype_r (plotter, 1);
- else
- pl_pentype_r (plotter, 0);
- plotter_visible_pen = visible;
- }
- }
- //////////////////////////////////////////////////////////////////////
- // TEXT
- //////////////////////////////////////////////////////////////////////
- // Draw a text object.
- void
- plot_output::text(const position ¢er, text_piece *v, int n, double angle)
- {
- int horizontal_adj, vertical_adj;
- double line_spacing;
- // convert from fraction of width of display, to virtual inches
- // also multiply by 1.2 (cf. 10pt with 12pt leading)
- line_spacing = 1.2 * (DISPLAY_SIZE_IN_INCHES * font_size);
- if (n > 0)
- {
- pl_ftextangle_r (plotter, 180 * angle / M_PI);
- plotter_path_in_progress = false;
- set_pen_visibility (true); // libplot may need this
- }
- for (int i = 0; i < n; i++)
- {
- pl_fmove_r (plotter,
- center.x - (0.5*(n-1) - i) * line_spacing * sin(angle),
- center.y + (0.5*(n-1) - i) * line_spacing * cos(angle));
- plotter_path_in_progress = false;
- switch ((int)(v[i].adj.h))
- {
- case (int)CENTER_ADJUST:
- default:
- horizontal_adj = 'c';
- break;
- case (int)LEFT_ADJUST:
- horizontal_adj = 'l';
- break;
- case (int)RIGHT_ADJUST:
- horizontal_adj = 'r';
- break;
- }
- switch ((int)(v[i].adj.v))
- {
- case (int)NONE_ADJUST:
- default:
- vertical_adj = 'c';
- break;
- case (int)ABOVE_ADJUST:
- vertical_adj = 'b';
- break;
- case (int)BELOW_ADJUST:
- vertical_adj = 't';
- break;
- }
- pl_alabel_r (plotter, horizontal_adj, vertical_adj, v[i].text);
- plotter_path_in_progress = false;
- }
- }
- //////////////////////////////////////////////////////////////////////
- // OPEN PIC OBJECTS
- //////////////////////////////////////////////////////////////////////
- // Draw a polyline ("open" in pic's sense, i.e., unfilled, may be part of a
- // continuing path).
- void
- plot_output::line(const position &start, const position *v, int n,
- const line_type <)
- {
- if (n == 0)
- return;
- if (lt.type == line_type::invisible)
- {
- pl_fmove_r (plotter, v[n-1].x, v[n-1].y);
- plotter_path_in_progress = false;
- return;
- }
- set_fill (-1.0); // unfilled, pic convention
- set_pen_visibility (true);
- if (!precision_dashing || lt.type == line_type::solid)
- {
- set_line_type_and_thickness (lt);
- pl_fline_r (plotter, start.x, start.y, v[0].x, v[0].y);
- for (int i = 1; i < n; i++)
- pl_fcont_r (plotter, v[i].x, v[i].y);
- plotter_path_in_progress = true;
- }
- else
- {
- switch (lt.type)
- {
- case line_type::dashed:
- {
- // edge polyline, with dashes
- line_type slt = lt;
- slt.type = line_type::solid;
- set_line_type_and_thickness (slt);
- position from_point = start, to_point = v[0];
- for (int i = 0; i < n; i++)
- {
- distance vec(to_point - from_point);
- double dist = hypot(vec);
- if (dist <= lt.dash_width*2.0)
- pl_fline_r (plotter,
- from_point.x, from_point.y, to_point.x, to_point.y);
- else
- {
- // round number of dashes to integer, along each segment
- int ndashes = int((dist - lt.dash_width)/(lt.dash_width*2.0) + .5);
- distance dash_vec = vec*(lt.dash_width/dist);
- double dash_gap = (dist - lt.dash_width)/ndashes;
- distance dash_gap_vec = vec*(dash_gap/dist);
- for (int j = 0; j <= ndashes; j++)
- {
- position s(from_point + dash_gap_vec*j);
- pl_fline_r (plotter,
- s.x, s.y, s.x + dash_vec.x, s.y + dash_vec.y);
- }
- }
- from_point = v[i];
- to_point = v[i+1];
- }
- pl_endpath_r (plotter);
- plotter_path_in_progress = false;
- }
- break;
- case line_type::dotted:
- {
- // edge polyline, with dots
- position from_point = start, to_point = v[0];
- for (int i = 0; i < n; i++)
- {
- distance vec(to_point - from_point);
- double dist = hypot(vec);
- // round dot spacings to integer, along line segment
- int ndots = IROUND(dist/lt.dash_width);
- if (ndots == 0)
- dot (from_point, lt);
- else
- {
- vec /= double(ndots);
- for (int j = 0; j <= ndots; j++)
- dot (from_point + vec*j, lt);
- }
- from_point = v[i];
- to_point = v[i+1];
- }
- }
- break;
- default:
- break;
- }
- }
- }
- // Draw a spline ("open" in pic's sense, i.e. unfilled, may be part
- // of a continuing path).
- void
- plot_output::spline(const position &start, const position *v, int n,
- const line_type <)
- {
- if (n == 0)
- return;
- if (lt.type == line_type::invisible)
- {
- pl_fmove_r (plotter, v[n-1].x, v[n-1].y);
- plotter_path_in_progress = false;
- return;
- }
- set_fill (-1.0); // unfilled, pic convention
- set_pen_visibility (true);
- set_line_type_and_thickness (lt);
- if (n == 1)
- pl_fline_r (plotter, start.x, start.y, v[0].x, v[0].y);
- else if (n == 2)
- pl_fbezier2_r (plotter,
- start.x, start.y, v[0].x, v[0].y, v[1].x, v[1].y);
- else
- {
- pl_fbezier2_r (plotter,
- start.x, start.y,
- v[0].x, v[0].y,
- 0.5 * (v[0].x + v[1].x), 0.5 * (v[0].y + v[1].y));
- for (int i = 0; i < n - 3; i++)
- pl_fbezier2_r (plotter,
- 0.5 * (v[i].x + v[i+1].x), 0.5 * (v[i].y + v[i+1].y),
- v[i+1].x, v[i+1].y,
- 0.5 * (v[i+1].x + v[i+2].x), 0.5 * (v[i+1].y + v[i+2].y));
- pl_fbezier2_r (plotter,
- 0.5 * (v[n-3].x + v[n-2].x), 0.5 * (v[n-3].y + v[n-2].y),
- v[n-2].x, v[n-2].y,
- v[n-1].x, v[n-1].y);
- }
- plotter_path_in_progress = true;
- }
- // Draw an arc object ("open" in pic's sense, i.e., unfilled, may
- // be part of a continuing path).
- void
- plot_output::arc (const position &start, const position ¢,
- const position &end, const line_type <)
- // in libplot, arcs don't subtend >= 180 degrees, but that's OK
- // because they don't subtend >=180 degrees in pic either
- {
- if (lt.type == line_type::invisible)
- {
- pl_fmove_r (plotter, end.x, end.y);
- plotter_path_in_progress = false;
- return;
- }
- set_fill (-1.0); // unfilled (pic convention)
- set_pen_visibility (true);
- if (!precision_dashing || lt.type == line_type::solid)
- {
- set_line_type_and_thickness (lt);
- pl_farc_r (plotter, cent.x, cent.y, start.x, start.y, end.x, end.y);
- plotter_path_in_progress = true;
- }
- else
- {
- line_type slt;
- slt = lt;
- slt.type = line_type::solid;
- set_line_type_and_thickness (slt);
- switch (lt.type)
- {
- case line_type::dashed:
- // edge arc, with dashes
- if (plotter_path_in_progress)
- pl_endpath_r (plotter);
- dashed_arc (start, cent, end, lt);
- pl_endpath_r (plotter);
- plotter_path_in_progress = false;
- break;
- case line_type::dotted:
- // edge arc, with dots
- dotted_arc (start, cent, end, lt);
- plotter_path_in_progress = false;
- break;
- default:
- break;
- }
- }
- }
- //////////////////////////////////////////////////////////////////////
- // CLOSED PIC OBJECTS
- // (some drawn differently if we do `precision dashing')
- //////////////////////////////////////////////////////////////////////
- // Draw a polyline object ("closed" in pic's sense).
- void
- plot_output::polygon(const position *v, int n,
- const line_type <, double fill)
- {
- if (lt.type == line_type::invisible)
- {
- pl_fmove_r (plotter, v[n-1].x, v[n-1].y);
- plotter_path_in_progress = false;
- return;
- }
- if (!precision_dashing || lt.type == line_type::solid)
- {
- set_fill (fill);
- set_pen_visibility (true);
- set_line_type_and_thickness (lt);
- if (n == 4
- && v[0].x == v[1].x && v[2].x == v[3].x
- && v[0].y == v[3].y && v[1].y == v[2].y)
- {
- pl_fbox_r (plotter, v[3].x, v[3].y, v[1].x, v[1].y);
- plotter_path_in_progress = false;
- }
- else
- {
- pl_fmove_r (plotter, v[n-1].x, v[n-1].y);
- for (int i = 0; i < n; i++)
- pl_fcont_r (plotter, v[i].x, v[i].y);
- pl_endpath_r (plotter);
- plotter_path_in_progress = false;
- }
- }
- else
- // precision dashing (or dotting)
- {
- line_type slt;
- if (fill >= 0.0)
- // fill polygon, but don't edge it
- {
- set_fill (fill);
- slt.type = line_type::solid;
- slt.thickness = 0.0;
- set_line_type_and_thickness (slt);
- set_pen_visibility (false); // edge will not be drawn
- pl_fmove_r (plotter, v[n-1].x, v[n-1].y);
- for (int i = 0; i < n; i++)
- pl_fcont_r (plotter, v[i].x, v[i].y);
- pl_endpath_r (plotter);
- plotter_path_in_progress = false;
- }
- // draw polygon boundary (unfilled)
- set_fill (-1.0);
- set_pen_visibility (true);
- switch (lt.type)
- {
- case line_type::dashed:
- {
- // edge polygon, with dashes
- slt = lt;
- slt.type = line_type::solid;
- set_line_type_and_thickness (slt);
- position from_point = v[n-1], to_point = v[0];
- for (int i = 0; i < n; i++)
- {
- distance vec(to_point - from_point);
- double dist = hypot(vec);
- if (dist <= lt.dash_width*2.0)
- pl_fline_r (plotter,
- from_point.x, from_point.y, to_point.x, to_point.y);
- else
- {
- // round number of dashes to integer, along each segment
- int ndashes = int((dist - lt.dash_width)/(lt.dash_width*2.0) + .5);
- distance dash_vec = vec*(lt.dash_width/dist);
- double dash_gap = (dist - lt.dash_width)/ndashes;
- distance dash_gap_vec = vec*(dash_gap/dist);
- for (int j = 0; j <= ndashes; j++)
- {
- position s(from_point + dash_gap_vec*j);
- pl_fline_r (plotter,
- s.x, s.y, s.x + dash_vec.x, s.y + dash_vec.y);
- }
- }
- from_point = v[i];
- to_point = v[i+1];
- }
- pl_endpath_r (plotter);
- plotter_path_in_progress = false;
- }
- break;
- case line_type::dotted:
- {
- // edge polygon, with dots
- position from_point = v[n-1], to_point = v[0];
- for (int i = 0; i < n; i++)
- {
- distance vec(to_point - from_point);
- double dist = hypot(vec);
- // round dot spacings to integer, along line segment
- int ndots = IROUND(dist/lt.dash_width);
- if (ndots == 0)
- dot (from_point, lt);
- else
- {
- vec /= double(ndots);
- for (int j = 0; j <= ndots; j++)
- dot (from_point + vec*j, lt);
- }
- from_point = v[i];
- to_point = v[i+1];
- }
- }
- break;
- default: // shouldn't happen
- break;
- }
- }
- }
- // Draw a circle object ("closed" in pic's sense).
- void
- plot_output::circle (const position ¢, double rad,
- const line_type <, double fill)
- {
- if (lt.type == line_type::invisible)
- {
- pl_fmove_r (plotter, cent.x, cent.y);
- plotter_path_in_progress = false;
- return;
- }
- if (!precision_dashing || lt.type == line_type::solid)
- {
- set_fill (fill);
- set_pen_visibility (true);
- set_line_type_and_thickness (lt);
- pl_fcircle_r (plotter, cent.x, cent.y, rad);
- plotter_path_in_progress = false;
- }
- else
- // precision dashing (or dotting)
- {
- line_type slt;
- if (fill >= 0.0)
- // fill circle, but don't edge it
- {
- set_fill (fill);
- set_pen_visibility (false); // edge will not be drawn
- slt = lt;
- slt.type = line_type::solid;
- slt.thickness = 0.0;
- set_line_type_and_thickness (slt);
- pl_fcircle_r (plotter, cent.x, cent.y, rad);
- plotter_path_in_progress = false;
- }
- // draw circle boundary (unfilled)
- set_fill (-1.0);
- set_pen_visibility (true);
- slt = lt;
- slt.type = line_type::solid;
- set_line_type_and_thickness (slt);
- switch (lt.type)
- {
- case line_type::dashed:
- // edge circle, with dashes
- if (plotter_path_in_progress)
- pl_endpath_r (plotter);
- dashed_circle(cent, rad, lt);
- pl_endpath_r (plotter);
- plotter_path_in_progress = false;
- break;
- case line_type::dotted:
- // edge circle, with dots
- dotted_circle (cent, rad, lt);
- break;
- default: // shouldn't happen
- break;
- }
- }
- }
- // Draw a rounded box object ("closed" in pic's sense).
- void
- plot_output::rounded_box(const position ¢, const distance &dim, double rad, const line_type <, double fill)
- {
- static bool recursive = false;
- position tem, arc_start, arc_cent, arc_end;
- position line_start, line_end;
- if (lt.type == line_type::invisible)
- {
- pl_fmove_r (plotter, cent.x, cent.y);
- plotter_path_in_progress = false;
- return;
- }
- if (plotter_path_in_progress)
- {
- pl_endpath_r (plotter);
- plotter_path_in_progress = false;
- }
- if (!precision_dashing || lt.type == line_type::solid)
- {
- set_fill (fill);
- if (!recursive)
- // _not_ invoked recursively on account of precision dashing
- {
- set_pen_visibility (true);
- set_line_type_and_thickness (lt);
- }
- tem = cent - dim/2.0;
- arc_start = tem + position(0.0, rad);
- arc_cent = tem + position(rad, rad);
- arc_end = tem + position(rad, 0.0);
- pl_farc_r (plotter, arc_cent.x, arc_cent.y,
- arc_start.x, arc_start.y, arc_end.x, arc_end.y);
- line_start = cent + position(-dim.x/2.0 + rad, -dim.y/2.0);
- line_end = cent + position(dim.x/2.0 - rad, -dim.y/2.0);
- pl_fline_r (plotter, arc_end.x, arc_end.y, line_end.x, line_end.y);
- tem = cent + position(dim.x/2.0, -dim.y/2.0);
- arc_start = tem + position(-rad, 0.0);
- arc_cent = tem + position(-rad, rad);
- arc_end = tem + position(0.0, rad);
- pl_farc_r (plotter, arc_cent.x, arc_cent.y,
- line_end.x, line_end.y, arc_end.x, arc_end.y);
- line_start = cent + position(dim.x/2.0, -dim.y/2.0 + rad);
- line_end = cent + position(dim.x/2.0, dim.y/2.0 - rad);
- pl_fline_r (plotter, arc_end.x, arc_end.y, line_end.x, line_end.y);
- tem = cent + dim/2.0;
- arc_start = tem + position(0.0, -rad);
- arc_cent = tem + position(-rad, -rad);
- arc_end = tem + position(-rad, 0.0);
- pl_farc_r (plotter, arc_cent.x, arc_cent.y,
- line_end.x, line_end.y, arc_end.x, arc_end.y);
- line_start = cent + position(dim.x/2.0 - rad, dim.y/2.0);
- line_end = cent + position(-dim.x/2.0 + rad, dim.y/2.0);
- pl_fline_r (plotter, arc_end.x, arc_end.y, line_end.x, line_end.y);
- tem = cent + position(-dim.x/2.0, dim.y/2.0);
- arc_start = tem + position(rad, 0.0);
- arc_cent = tem + position(rad, -rad);
- arc_end = tem + position(0.0, -rad);
- pl_farc_r (plotter, arc_cent.x, arc_cent.y,
- line_end.x, line_end.y, arc_end.x, arc_end.y);
- line_start = cent + position(-dim.x/2.0, dim.y/2.0 - rad);
- line_end = cent + position(-dim.x/2.0, -dim.y/2.0 + rad);
- pl_fline_r (plotter, arc_end.x, arc_end.y, line_end.x, line_end.y);
- pl_endpath_r (plotter);
- plotter_path_in_progress = false;
- }
- else
- // precision dashing (or dotting)
- {
- if (fill >= 0.0)
- {
- // fill rounded box (boundary solid, thickness 0) via recursive call
- set_fill (fill);
- set_pen_visibility (false); // edge will not be drawn
- line_type slt = lt;
- slt.type = line_type::solid;
- slt.thickness = 0.0;
- recursive = true;
- rounded_box(cent, dim, rad, slt, fill);
- recursive = false;
- plotter_path_in_progress = false;
- }
- // draw rounded box boundary, unfilled
- set_pen_visibility (true);
- set_line_type_and_thickness (lt); // only thickness is relevant
- common_output::rounded_box(cent, dim, rad, lt, -1.0); //-1 means unfilled
- if (plotter_path_in_progress)
- {
- pl_endpath_r (plotter);
- plotter_path_in_progress = false;
- }
- }
- }
- // Draw an ellipse object ("closed" in pic's sense).
- // No support for precision dashing, but there should be.
- void
- plot_output::ellipse(const position ¢, const distance &dim,
- const line_type <, double fill)
- {
- if (lt.type == line_type::invisible)
- {
- pl_fmove_r (plotter, cent.x, cent.y);
- plotter_path_in_progress = false;
- return;
- }
- set_fill (fill);
- set_pen_visibility (true);
- set_line_type_and_thickness (lt);
- pl_fellipse_r (plotter, cent.x, cent.y, 0.5 * dim.x, 0.5 * dim.y, 0.0);
- plotter_path_in_progress = false;
- }
- //////////////////////////////////////////////////////////////////////
- // MISC.
- //////////////////////////////////////////////////////////////////////
- // Internal function, used for precision dotting; also invoked by
- // precision dotting methods in the common_output superclass.
- void
- plot_output::dot (const position ¢, const line_type <)
- // lt arg determines diameter of dot
- {
- line_type slt;
-
- set_fill (1.0);
- set_pen_visibility (true);
- slt.type = line_type::solid;
- slt.thickness = 0.0;
- set_line_type_and_thickness (slt);
- pl_fcircle_r (plotter, cent.x, cent.y, 0.5 * lt.thickness / POINTS_PER_INCH);
- plotter_path_in_progress = false;
- }
- int
- plot_output::supports_filled_polygons()
- {
- return 1;
- }
|