1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
|
// 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 (display_type, 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;
}
|