libplot
, a Function Librarylibplot
: An overview
GNU libplot
is a free function library for drawing
two-dimensional vector graphics. It can produce smooth, double-buffered
animations for the X Window System, and can export files in many
graphics file formats. It is `device-independent' in the sense that
its API (application programming interface) is to a large extent
independent of the display type or output format.
There are bindings for C, C++, and other languages. The C binding,
which is the most frequently used, is also called libplot
, and
the C++ binding, when it needs to be distinguished, is called
libplotter
. In this section we use libplot
to refer
to the library itself, irrespective of binding.
The graphical objects that libplot
can draw include paths,
circles and ellipses, points, markers, and `adjusted labels' (justified
text strings). A path is a sequence of line segments,
circular arcs, elliptic arcs, quadratic Bezier curves, and/or cubic
Bezier curves. Paths may be open or closed. User-specified filling of
paths, circles, and ellipses is supported (fill rule and fill color,
as well as pen color, may be specified). There is support for
maintaining a Postscript-style stack of graphics contexts, i.e., a
stack of drawing attribute sets. Path-related attributes include line
thickness, line type, cap type, and join type, and text-related
attributes include font name, font size, and text angle.
The fundamental abstraction provided by libplot
is that of a
Plotter. A Plotter is an object with an interface for the
drawing of vector graphics which is similar to the interface provided by
a traditional pen plotter. There are many types of Plotter, which
differ in the output format they produce. Any number of Plotters, of
the same or different types, may exist simultaneously in an application.
The drawing operations supported by Plotters of different types are
identical, in agreement with the principle of device independence.
So a graphics application that is linked with libplot
may
easily be written so as to produce output in any or all of the
supported output formats.
The following are the currently supported types of Plotter.
xv
.
xv
. The
creation of animated pseudo-GIFs is supported.
idraw
drawing editor.
xfig
drawing editor. The
xfig
editor will export drawings in various other formats for
inclusion in documents.
xterm
, the X Window System terminal
emulation program. The MS-DOS version of kermit
also includes
such an emulator.
plot
.
(See section The plot
Program.)
A distinction among these types of Plotter is that all except X and X Drawable Plotters write graphics to a file or other output stream. An X Plotter pops up its own windows, and an X Drawable Plotter draws graphics in one or two X drawables.
Another distinction is that the first four types of Plotter (X, X Drawable, PNM, and GIF) produce bitmap output, while the remaining types produce output in a vector graphics format. In bitmap output the structure of the graphical objects is lost, but in a vector format it is retained.
An additional distinction is that X, X Drawable, Tektronix and Metafile Plotters are real-time. This means that they draw graphics or write to an output stream as the drawing operations are invoked on them. The remaining types of Plotter are not real-time, since their output streams can only be emitted after all functions have been called. For PNM and GIF Plotters, this is because the bitmap must be constructed before it is written out. For Illustrator and Postscript Plotters, it is because a `bounding box' line must be placed at the head of the output file. For a Fig Plotter, it is because color definitions must be placed at the head of the output file.
The most important operations supported by any Plotter are openpl
and closepl
, which open and close it. Graphics may be drawn,
and drawing attributes set, only within an
openpl
...closepl
pair. The graphics produced within
each openpl
...closepl
pair constitute a `page'. In
principle, any Plotter may be opened and closed arbitrarily many times.
An X Plotter displays each page in a separate X window, and
Postscript, PCL, and HP-GL Plotters render each page as a separate
physical page. X Drawable Plotters and Tektronix Plotters
manipulate a single drawable or display, on which pages are displayed in
succession. Plotters that do not draw in real time (PNM, GIF,
Illustrator, Postscript, Fig, PCL, and HP-GL Plotters) may wait until
their existence comes to an end (i.e., until they are deleted) before
outputting their pages of graphics.
In the current release of libplot
, Postscript Plotters delay
outputting graphics in this way, but PCL and HP-GL Plotters output each
page of graphics individually, i.e., when closepl
is invoked.
PNM, GIF, Illustrator and Fig Plotters are similar, but output only the
first page. That is because PNM, GIF, Illustrator and Fig formats
support only a single page of graphics.
There are several other basic operations which any Plotter supports. The `graphics display' drawn in by a Plotter is a square or rectangular region on a display device. But when using any Plotter to draw graphics, a user will specify the coordinates of graphical objects in device-independent `user coordinates', rather than in device coordinates. A Plotter relates the user coordinate system to the device coordinate system by performing an affine transformation, which must be specified by the user.
Immediately after invoking openpl
to open a Plotter, an
application should invoke the space
operation to initialize this
transformation. This invocation specifies the rectangular region (in
user coordinates) that will be mapped by the Plotter to the graphics
display. The affine transformation may be updated at any later time by
invoking space
again, or by invoking fconcat
. The
fconcat
operation will `concatenate' (i.e., compose) the current
affine transformation with any specified affine transformation. This
sort of concatenation is a capability familiar from, e.g., Postscript.
Each Plotter maintains a Postscript-style stack of graphics contexts.
This makes possible the rapid, efficient drawing of complicated pages of
graphics. A graphics context includes the current affine
transformation from the user coordinate system to the device coordinate
system. It also includes such modal drawing attributes as graphics
cursor position, linemode, line thickness, pen and fill colors, and the
font used for drawing text. The state of any uncompleted path (if
any) is included as well, since paths may be drawn incrementally,
one portion (line segment or arc) at a time. The current graphics
context is pushed onto the stack by calling savestate
, and popped
off by calling restorestate
.
To permit vector graphics animation, any page of graphics may be split
into `frames'. A frame is ended, and a new frame is begun, by
invoking the erase
operation. On a Plotter that does
real-time plotting (i.e., an X, X Drawable, Tektronix, or
Metafile Plotter), this erases all plotted objects from the graphics
display, allowing a new frame to be drawn. Displaying a sequence of
frames in succession creates the illusion of smooth animation.
On most Plotters that do not do real-time plotting (i.e., PNM,
Illustrator, Postscript, Fig, PCL, or HP-GL Plotters), invoking
erase
deletes all plotted objects from an internal buffer. For
this reason, most Plotters that do not do real-time plotting will
display only the final frame of any multiframe page.
GIF Plotters are in a class by themselves. Even though they do not do
real time plotting, a GIF Plotter can produce multi-image output,
i.e., an animated pseudo-GIF file, from a multiframe page. As noted
above, the pseudo-GIF file produced by a GIF Plotter will contain only
the first page of graphics. But if this page consists of multiple
frames, then each invocation of erase
, after the first, will be
treated by default as a separator between successive images.
libplot
libplot
has bindings for several programming languages.
Regardless of which language binding is used, the concepts behind
libplot
(Plotters, and a fixed set of operations that can be
applied to any Plotter) remain the same. However, the ways in which
Plotters are manipulated (created, selected for use, and deleted)
may differ between bindings. This section discusses the C binding.
If you are writing an application in C that will use libplot
to
draw vector graphics, the first thing you need to know is how, in the
C binding, Plotters are manipulated. There are four special
functions for this, which you can invoke: newpl
, selectpl
,
deletepl
, and the parameter-setting function parampl
.
Actually, you would usually invoke them under the names pl_newpl
,
pl_selectpl
, pl_deletepl
, and pl_parampl
. That is
because in the C binding, the names of all functions begin with "pl_"
unless the header file plotcompat.h
is included. See section C compiling and linking.
The pl_newpl
function will create a Plotter of specified type.
Its first argument may be "X", "Xdrawable", "pnm", "gif", "ai", "ps",
"fig", "pcl", "hpgl", "tek", or "meta". It returns a nonnegative
integer (a "handle") that may be used to refer to the Plotter.
Before using a Plotter that you have created (i.e., before invoking any
of the libplot
operations on it), you must select the Plotter
for use by calling pl_selectpl
. Only one Plotter may be
selected at a time, but by calling pl_selectpl
you may switch
from Plotter to Plotter at any time, even when the selected Plotter is
open. A Plotter that is not currently selected can be deleted, and
its storage freed, by calling pl_deletepl
.
Strictly speaking, you do not need to call pl_newpl
,
pl_selectpl
, or pl_deletepl
in order to draw graphics.
That is because at startup, a single Metafile Plotter that writes to
standard output (with handle `0') is automatically created and
selected. The presence of this default Plotter is for compatibility
with pre-GNU versions of libplot
. Of course, you may not
wish to obtain output in metafile format, and you may not wish to write
to standard output.
You should get into the habit of calling pl_deletepl
whenever you
are finished using a Plotter. In general, Plotters that do not plot
graphics in real time (Postscript Plotters in particular) write out
graphics only when the plot is finished, and pl_deletepl
is
called.
The following table summarizes the action of the four functions in the C binding that are used for Plotter manipulation.
libplot
operations is subsequently invoked,
it will be applied to the selected Plotter. Only one Plotter may be
selected at a time. At startup, a single Metafile Plotter that writes
to standard output (with handle `0') is automatically created and
selected.
The handle of the previously selected Plotter is returned. A negative
return value indicates the specified Plotter does not exist or could not
be selected.
char *
, i.e., a string. Unrecognized parameters are
ignored. For a list of the recognized parameters and their meaning, see
section Device driver parameters.
Up to now we have not discussed the fourth function, pl_parampl
.
Even though the Plotter interface is largely Plotter-independent, it
is useful to be able to specify certain aspects of a Plotter's behavior
at the time it is created. Plotter behavior is captured by a manageable
number of parameters, which we call device driver parameters.
A value for any parameter can be specified by calling
pl_parampl
. This function does not operate on any particular
Plotter: it belongs to the C binding as a whole. The parameter
values used by any Plotter are constant over the lifetime of the
Plotter, and are those that were in effect when the Plotter was created.
Actually, a slightly more sophisticated rule applies. If at Plotter
creation time a parameter is set, the value specified by the most recent
call to pl_parampl
will be the value used by the Plotter. If at
Plotter creation time a parameter is not set, its default value
will be used, unless the parameter is string-valued and there is an
environment variable of the same name, in which case the value of that
environment variable will be used. This rule increases run-time
flexibility: an application programmer may allow non-critical driver
parameters to be specified by the user via environment variables. Once
set, a parameter may be unset by the programmer by calling
pl_parampl
with a value argument of NULL. This further increases
flexibility.
The source code for a graphics application written in C, if it is to use
libplot
, must contain the lines
#include <stdio.h> #include <plot.h>
The header file plot.h
is distributed with libplot
, and
should have been installed on your system where your C compiler will
find it. It contains prototypes for each of the functions in
libplot
, and some miscellaneous definitions.
In current releases of libplot
, the names of all functions begin
with the prefix "pl_". For example, the openpl
operation is
invoked on a Plotter by calling the function pl_openpl
. If you
wish, you may maintain backward compatibility by also including the
header file plotcompat.h
. This header file redefines
openpl
as pl_openpl
, and similarly for the other
libplot
functions.
To link your application with libplot
, you would use the
appropriate `-l' option(s) on the command line when compiling it.
You would use
-lplot -lXaw -lXmu -lXt -lXext -lX11 -lm
or, in recent releases of the X Window System,
-lplot -lXaw -lXmu -lXt -lSM -lICE -lXext -lX11 -lm
(Alternatively, you may need to use `-lplot -lXm -lXt -lXext -lX11 -lm', `-lplot -lXm -lXt -lXext -lX11 -lm -lc -lgen', or `-lplot -lXm -lXt -lXext -lX11 -lm -lc -lPW', on systems that provide Motif widgets instead of Athena widgets. In recent releases of the X Window System, you would insert `-lSM -lICE'. Recent releases of Motif require `-lXp' as well.)
On some platforms, the directories in which libplot
or the other
libraries are stored must be specified on the command line. For
example, the options `-lXaw -lXmu -lXt -lSM -lICE -lXext -lX11',
which specify X Window System libraries, may need to be preceded by
an option like `-L/usr/X11/lib'.
On most systems libplot
is installed as a DLL (dynamically linked
library, or `shared' library). This means that the linking with your
application will take place at run time rather than compile time. The
environment variable LD_LIBRARY_PATH
lists the directories which
will be searched for DLL's at run time. For your application to be
executable, this environment variable should include the directory in
which libplot
is stored.
The following is a sample application, written in C, that invokes
libplot
operations to draw vector graphics. It draws an
intricate and beautiful path (Bill Gosper's "C" curve, discussed
as Item #135 in HAKMEM, MIT Artificial Intelligence Laboratory
Memo #239, 1972). As the numeric constant MAXORDER
(here
equal to 12) is increased, the path will take on the shape of a
curly letter "C", which is the envelope of a myriad of epicyclic
octagons.
#include <stdio.h> #include <plot.h> #define MAXORDER 12 void draw_c_curve (double dx, double dy, int order) { if (order >= MAXORDER) pl_fcontrel (dx, dy); /* continue path along (dx, dy) */ else { draw_c_curve (0.5 * (dx - dy), 0.5 * (dx + dy), order + 1); draw_c_curve (0.5 * (dx + dy), 0.5 * (dy - dx), order + 1); } } int main () { int handle; /* set a Plotter parameter */ pl_parampl ("PAGESIZE", "letter"); /* create a Postscript Plotter that writes to standard output */ if ((handle = pl_newpl ("ps", stdin, stdout, stderr)) < 0) { fprintf (stderr, "Couldn't create Plotter\n"); return 1; } pl_selectpl (handle); /* select the Plotter for use */ if (pl_openpl () < 0) /* open Plotter */ { fprintf (stderr, "Couldn't open Plotter\n"); return 1; } pl_fspace (0.0, 0.0, 1000.0, 1000.0); /* specify user coor system */ pl_flinewidth (0.25); /* line thickness in user coordinates */ pl_pencolorname ("red"); /* path will be drawn in red */ pl_erase (); /* erase Plotter's graphics display */ pl_fmove (600.0, 300.0); /* position the graphics cursor */ draw_c_curve (0.0, 400.0, 0); if (pl_closepl () < 0) /* close Plotter */ { fprintf (stderr, "Couldn't close Plotter\n"); return 1; } pl_selectpl (0); /* select default Plotter */ if (pl_deletepl (handle) < 0) /* delete Plotter we used */ { fprintf (stderr, "Couldn't delete Plotter\n"); return 1; } return 0; }
As you can see, this application begins by calling the pl_newpl
function to create a Postscript Plotter. The Postscript Plotter will
produce output for a US letter-sized page, though any other standard
page size, e.g., "a4", could be substituted. This would be arranged by
altering the call to pl_parampl
. The PAGESIZE
parameter
is one of several Plotter parameters that an application programmer may
set by calling pl_parampl
. For a complete list, see section Device driver parameters.
After the Plotter is created, the application selects it for use,
opens it, and draws the "C" curve recursively. The drawing of
the curve is accomplished by calling the pl_fmove
function to
position the Plotter's graphics cursor, and then calling
draw_c_curve
. This subroutine repeatedly calls
pl_fcontrel
. The pl_fcontrel
function continues a path by
adding a line segment to it. The endpoint of each line segment is
specified in relative coordinates, i.e., as an offset from the previous
cursor position. After the "C" curve is drawn, the Plotter is
closed. A Postscript file is written to standard output when
pl_deletepl
is called to delete the Plotter.
Specifying "pnm", "gif", "ai", "fig", "pcl", "hpgl", "tek", or "meta" as
the first argument in the call to pl_newpl
, instead of "ps",
would yield a Plotter that would write graphics to standard output in
the specified format, instead of Postscript. The PAGESIZE
parameter is relevant to the "ai", "fig", "pcl", and "hpgl" output
formats, but is ignored for the others. Specifying "meta" as the
Plotter type may be useful if you wish to avoid recompilation for
different output devices. Graphics metafile output may be piped to the
plot
utility and converted to any other supported output format,
or displayed in an X window. See section The plot
Program.
If "X" were specified as the first argument of pl_newpl
, the
curve would be drawn in a popped-up X window, and the output stream
argument would be ignored. Which X Window System display the window
would pop up on would be determined by the DISPLAY
parameter,
or if that parameter were not set, by the DISPLAY
environment
variable. The size of the X window would be determined by the
BITMAPSIZE
parameter, or if that parameter were not set, by the
BITMAPSIZE
environment variable. The default value is "570x570".
For the "pnm" and "gif" Plotter types, the interpretation of
BITMAPSIZE
is similar.
You could also specify "Xdrawable" as the Plotter type. For you to make
this work, you would need to know a bit about X Window System
programming. You would need to create at least one X drawable
(i.e., window or a pixmap), and by invoking the pl_parampl
function before newpl
is called, set it as the value of the
parameter XDRAWABLE_DRAWABLE1
or XDRAWABLE_DRAWABLE2
. For
the parameters that affect X Drawable Plotters, see section Device driver parameters.
The following is another sample application, written in C, that invokes
libplot
operations to draw vector graphics. It draws a
spiral consisting of elliptically boxed text strings, each of which
reads "GNU libplot!". This figure will be sent to standard output in
Postscript format.
#include <stdio.h> #include <plot.h> #include <math.h> #define SIZE 100.0 /* nominal size of user coordinate frame */ #define EXPAND 2.2 /* expansion factor for elliptical box */ void draw_boxed_string (char *s, double size, double angle) { double true_size, width; pl_ftextangle (angle); /* text inclination angle (degrees) */ true_size = pl_ffontsize (size); /* choose font size */ width = pl_flabelwidth (s); /* compute width of text string */ pl_fellipserel (0.0, 0.0, /* draw surrounding ellipse */ EXPAND * 0.5 * width, EXPAND * 0.5 * true_size, angle); pl_alabel ('c', 'c', s); /* draw centered text string */ } int main() { int handle, i; /* set a Plotter parameter */ pl_parampl ("PAGESIZE", "letter"); /* create a Postscript Plotter that writes to standard output */ if ((handle = pl_newpl ("ps", stdin, stdout, stderr)) < 0) { fprintf (stderr, "Couldn't create Plotter\n"); return 1; } pl_selectpl (handle); /* select the Plotter for use */ if (pl_openpl () < 0) /* open Plotter */ { fprintf (stderr, "Couldn't open Plotter\n"); return 1; } pl_fspace (-(SIZE), -(SIZE), SIZE, SIZE); /* spec. user coor system */ pl_pencolorname ("blue"); /* pen color will be blue */ pl_fillcolorname ("white"); pl_filltype (1); /* ellipses will be filled with white */ pl_fontname ("NewCenturySchlbk-Roman"); /* choose a Postscript font */ for (i = 80; i > 1; i--) /* loop through angles */ { double theta, radius; theta = 0.5 * (double)i; /* theta is in radians */ radius = SIZE / pow (theta, 0.35); /* this yields a spiral */ pl_fmove (radius * cos (theta), radius * sin (theta)); draw_boxed_string ("GNU libplot!", 0.04 * radius, (180.0 * theta / M_PI) - 90.0); } if (pl_closepl () < 0) /* close Plotter */ { fprintf (stderr, "Couldn't close Plotter\n"); return 1; } pl_selectpl (0); if (pl_deletepl (handle) < 0) /* delete Plotter we used */ { fprintf (stderr, "Couldn't delete Plotter\n"); return 1; } return 0; }
This example shows what is involved in plotting a text string or text
strings. First, the desired font must be retrieved. A font is
fully specified by calling pl_fontname
, pl_fontsize
, and
pl_textangle
, or their floating point counterparts
pl_ffontname
, pl_ffontsize
, and pl_ftextangle
.
Since these three functions may be called in any order, each of them
returns the size of the font that it selects, as a convenience to the
programmer. This may differ slightly from the size specified in the
most recent call to pl_fontsize
or pl_ffontsize
, since
many Plotters have only a limited repertory of fonts. The above example
plots each text string in the "NewCenturySchlbk-Roman" font, which is
available on Postscript Plotters. See section Available text fonts.
If you replace "ps" by "X" in the call to pl_newpl
, an X
Plotter rather than a Postscript Plotter will be used, and the spiral
will be drawn in a popped-up X window. If your X display does
not support the "NewCenturySchlbk-Roman" font, you may substitute any
other scalable font, such as the widely available
"utopia-medium-r-normal". For the format of font names, see section Available text fonts for the X Window System. If the X Plotter is unable to retrieve the font
you specify, it will first attempt to use a default scalable font
("Helvetica"), and if that fails, use a default Hershey vector font
("HersheySerif") instead. Hershey fonts are constructed from line
segments, so each built-in Hershey font is available on all types of
Plotter.
If you are using an older (pre-X11R6) X Window System display, you will find that retrieving a scalable font is a time-consuming operation. The above example may run slowly on some older X displays, since a new font must be retrieved before each text string is drawn. That is because each text string has a different angle of inclination. It is possible to retrieve individual characters from an X11R6 display, rather than retrieving an entire rasterized font. If this feature is available, the X Plotter will automatically take advantage of it to save time.
Using libplot
to create pseudo-GIF files, including animated
pseudo-GIFs, is straightforward. A GIF Plotter is a Plotter like
any other, and it supports the same drawing operations. However, it has
two special properties. (1) It can draw only a single page of
graphics, i.e., only the graphics contained in the first
openpl
...closepl
appear in the output file. In
this, it resembles other Plotters that do not plot in real time.
(2) Within this page, each invocation of erase
is normally
treated as the beginning of a new image in the output file. There is an
exception to this: the first invocation of erase
begins a new
image only if something has already been drawn.
The reason for the exception is that many programmers who use
libplot
are in the habit of invoking erase
immediately
after a Plotter is opened. This is not a bad habit, since a few types
of Plotter (e.g., X Drawable and Tektronix Plotters) are
`persistent' in the sense that previously drawn graphics remain visible.
The following program creates a simple animated pseudo-GIF, 150 pixels wide and 100 pixels high.
#include <stdio.h> #include <plot.h> int main() { int i, handle; /* set Plotter parameters */ pl_parampl ("BITMAPSIZE", "150x100"); pl_parampl ("BG_COLOR", "orange"); pl_parampl ("TRANSPARENT_COLOR", "orange"); pl_parampl ("GIF_ITERATIONS", "100"); pl_parampl ("GIF_DELAY", "5"); /* create a GIF Plotter with the specified parameters */ handle = pl_newpl ("gif", stdin, stdout, stderr); pl_selectpl (handle); /* select the Plotter for use */ pl_openpl(); /* begin page of graphics */ pl_space (0, 0, 149, 99); /* specify user coordinate system */ pl_pencolorname ("red"); /* objects will be drawn in red */ pl_linewidth (5); /* set the line thickness */ pl_filltype (1); /* objects will be filled */ pl_fillcolorname ("black"); /* set the fill color */ for (i = 0; i < 180 ; i += 15) { pl_erase (); /* begin new GIF image */ pl_ellipse (75, 50, 40, 20, i); /* draw an ellipse */ } pl_closepl (); /* end page of graphics */ pl_selectpl (0); /* select default Plotter */ pl_deletepl (handle); /* delete Plotter we used */ return 0; }
The animated pseudo-GIF will be written to standard output. It will consist of twelve images, showing the counterclockwise rotation of a black-filled red ellipse through 180 degrees. The pseudo-GIF will be `looped' (see below), so the ellipse will rotate repeatedly.
The parameters of the ellipse are expressed in terms of user
coordinates, not pixel coordinates. But the call to pl_space
defines user and pixel coordinates to be effectively the same. User
coordinates are chosen so that the lower left corner is (0,0) and the
upper right corner is (149,99). Since this agrees with the image size,
individual pixels may be addressed in terms of integer user coordinates.
For example, pl_point(149,99)
would set the pixel in the
upper right hand corner of the image to the current pen color.
Besides BITMAPSIZE
and BG_COLOR
, there are several
important GIF Plotter parameters that may be set with the
pl_parampl
function. The TRANSPARENT_COLOR
parameter may
be set to the name of a color. Pixels in a pseudo-GIF that have that
color will be treated as transparent by most software. This is usually
used to create a transparent background. In the example above, the
background color is specified as orange, but the transparent color is
also specified as orange. So the background will not actually be
displayed.
The GIF_ITERATIONS
parameter, if set, specifies the number of
times that a multi-frame pseudo-GIF should be looped. The
GIF_DELAY
parameter specifies the number of hundredths of a
seconds that should elapse between successive images.
The INTERLACE
parameter is sometimes useful. If it is set to
"yes", the pseudo-GIF will be interlaced. This is of greatest value for
single-frame GIFs. For full details on Plotter parameters, see
section Device driver parameters.
You may use libplot
to produce vector graphics animations on any
Plotter that does real-time plotting (i.e., an X, X Drawable,
Tektronix, or Metafile Plotter). By definition, the `frames' in any
page of graphics are separated by invocations of erase
. So
the graphics display will be cleared after each frame. If successive
frames differ only slightly, a smooth animation will result.
The following is a sample application, written in C, that produces an animation for the X Window System. It displays a `drifting eye'. As the eye drifts across a popped-up window from left to right, it slowly rotates. After the eye has drifted across twice, the window will vanish.
#include <stdio.h> #include <plot.h> int main () { int handle, i = 0, j; /* set Plotter parameters */ pl_parampl ("BITMAPSIZE", "300x150"); pl_parampl ("VANISH_ON_DELETE", "yes"); pl_parampl ("USE_DOUBLE_BUFFERING", "yes"); /* create an X Plotter with the specified parameters */ if ((handle = pl_newpl ("X", stdin, stdout, stderr)) < 0) { fprintf (stderr, "Couldn't create Plotter\n"); return 1; } pl_selectpl (handle); /* select the Plotter for use */ if (pl_openpl () < 0) /* open Plotter */ { fprintf (stderr, "Couldn't open Plotter\n"); return 1; } pl_space (0, 0, 299, 149); /* specify user coordinate system */ pl_linewidth (8); /* line thickness in user coordinates */ pl_filltype (1); /* objects will be filled */ pl_bgcolorname ("saddle brown"); /* background color for the window*/ for (j = 0; j < 300; j++) { pl_erase (); /* erase window */ pl_pencolorname ("red"); /* choose red pen, with cyan filling */ pl_fillcolorname ("cyan"); pl_ellipse (i, 75, 35, 50, i); /* draw an ellipse */ pl_colorname ("black"); /* choose black pen, with black filling */ pl_circle (i, 75, 12); /* draw a circle [the pupil] */ i = (i + 2) % 300; /* shift rightwards */ } if (pl_closepl () < 0) /* close Plotter */ { fprintf (stderr, "Couldn't close Plotter\n"); return 1; } pl_selectpl (0); /* select default Plotter */ if (pl_deletepl (handle) < 0) /* delete Plotter we used */ { fprintf (stderr, "Couldn't delete Plotter\n"); return 1; } return 0; }
As you can see, this application begins by calling pl_parampl
several times to set device driver parameters, and then calls
pl_newpl
to create an X Plotter. The X Plotter window
will have size 300x150 pixels. This window will vanish when the Plotter
is deleted. If the VANISH_ON_DELETE
parameter were not set
to "yes", the window would remain on the screen until removed by the
user (by typing `q' in it, or by clicking with a mouse).
Setting the parameter USE_DOUBLE_BUFFERING
to "yes" requests that
double buffering be used. This is very important if you wish to produce
a smooth animation, with no jerkiness. Normally, an X Plotter draws
graphics into a window in real time, and erases the window when
pl_erase
is called. But if double buffering is used, each frame
of graphics is written into an off-screen buffer, and is copied into the
window, pixel by pixel, when pl_erase
is called or the Plotter is
closed. This is a bit counterintuitive, but is exactly what is needed
for smooth animation.
After the Plotter is created, it is selected for use and opened. When
pl_openpl
is called, the window pops up, and the animation
begins. In the body of the for loop there is a call to
pl_erase
, and also a sequence of libplot
operations that
draws the eye. The pen color and fill color are changed twice with each
passage through the loop. You may wish to experiment with the animation
parameters to produce the best effects on your video hardware.
The locations of the objects that are plotted in the animation are
expressed in terms of user coordinates, not pixel coordinates. But the
call to pl_space
defines user and pixel coordinates to be
effectively the same. User coordinates are chosen so that the lower
left corner is (0,0) and the upper right corner is (299,149). Since
this agrees with the window size, individual pixels may be addressed in
terms of integer user coordinates. For example,
pl_point(299,149)
would set the pixel in the upper right hand
corner of the window to the current pen color.
The following is another sample animation, this time of a rotating letter `A'.
#include <stdio.h> #include <plot.h> int main() { int handle, angle = 0; /* set Plotter parameters */ pl_parampl ("BITMAPSIZE", "300x300"); pl_parampl ("BG_COLOR", "blue"); /* background color for window */ pl_parampl ("USE_DOUBLE_BUFFERING", "yes"); /* create an X Plotter with the specified parameters */ handle = pl_newpl ("X", stdin, stdout, stderr); pl_selectpl (handle); /* open X Plotter, initialize coordinates, pen, and font */ pl_openpl (); pl_fspace (0.0, 0.0, 1.0, 1.0); /* use normalized coordinates */ pl_pencolorname ("white"); pl_ffontsize (1.0); pl_fontname ("NewCenturySchlbk-Roman"); pl_fmove (.50,.50); /* move to center */ while (1) /* loop endlessly */ { pl_erase (); pl_textangle (angle++); /* set new rotation angle */ pl_alabel ('c', 'c', "A"); /* draw a centered `A' */ } pl_closepl(); /* close Plotter */ pl_selectpl (0); /* select default Plotter */ pl_deletepl (handle); /* delete Plotter we used */ return 0; }
This animation serves as a good test of the capabilities of an X Window System display. On a modern X11R6 display, animation will be smooth and fast. That is because X11R6 displays can rasterize individual characters from a font without rasterizing the entire font. If your X display does not support the "NewCenturySchlbk-Roman" font, you may substitute any other scalable font, such as the widely available "utopia-medium-r-normal". For the format of font names, see section Available text fonts for the X Window System. If the X Plotter is unable to retrieve the font you specify, it will first attempt to use a default scalable font ("Helvetica"). If that too fails, it will use a default Hershey vector font ("HersheySerif") instead.
Animations that use Hershey fonts are normally faster than ones that use Postscript fonts or other X Window System fonts, since the Hershey fonts are constructed from line segments. Rasterizing line segments can be done rapidly. But if you use a scalable font such as "NewCenturySchlbk-Roman" or "utopia-medium-r-normal", you will notice that the rotation speeds up after the letter `A' has rotated through 360 degrees. That is because the `A' at angles past 360 degrees has already been rasterized.
Applications that run under the X Window System are normally built using Xt, the X Toolkit. In Xt, an application is constructed from `widgets' such as text entry fields, buttons, sliders, drawing areas, etc. When the application starts up, each widget is configured to respond appropriately to `events', which include key presses and mouse clicks. After the widgets are configured, control is transferred to the Xt event loop.
GNU libplot
can be used within the Xt event loop to draw vector
graphics. For this, it would use one or more X Drawable Plotters.
An X Drawable Plotter is a Plotter that can plot into an off-screen
pixmap or an on-screen window, such as a window associated with a
widget.
The following sample application shows how an X Drawable Plotter would be used. The application draws a `C' curve, as defined in a previous section, in a popped-up window. The usual Xt command-line options may be used: the window background color is specified with the `-bg' option, the window geometry with `-geometry', etc. The curve is initially drawn in red, but clicking once with the mouse will redraw it in green. A second mouse click will redraw it in red, and so forth. The application will terminate when `q' is typed.
#include <stdio.h> #include <plot.h> #include <X11/Xlib.h> #include <X11/Intrinsic.h> #include <X11/Shell.h> #include <X11/StringDefs.h> #include <X11/Core.h> int green = 0; /* draw in green, not red? */ #define MAXORDER 12 void draw_c_curve (double dx, double dy, int order) { if (order >= MAXORDER) pl_fcontrel (dx, dy); /* continue path along (dx, dy) */ else { draw_c_curve (0.5 * (dx - dy), 0.5 * (dx + dy), order + 1); draw_c_curve (0.5 * (dx + dy), 0.5 * (dy - dx), order + 1); } } void Redraw (Widget w, XEvent *ev, String *params, Cardinal *n_params) { /* draw C curve */ pl_erase (); pl_pencolorname (green ? "green" : "red"); pl_fmove (600.0, 300.0); draw_c_curve (0.0, 400.0, 0); pl_endpath (); } void Toggle (Widget w, XEvent *ev, String *params, Cardinal *n_params) { green = (green ? 0 : 1); Redraw (w, ev, params, n_params); } void Quit (Widget w, XEvent *ev, String *params, Cardinal *n_params) { exit (0); } /* mapping of events to actions */ static const String translations = "<Expose>: redraw()\n\ <Btn1Down>: toggle()\n\ <Key>q: quit()"; /* mapping of actions to subroutines */ static XtActionsRec actions[] = { {"redraw", Redraw}, {"toggle", Toggle}, {"quit", Quit}, }; /* default parameters for widgets */ static String default_resources[] = { "Example*geometry: 250x250", (String)NULL }; int main (int argc, char *argv[]) { Arg wargs[10]; /* storage of widget args */ Display *display; /* X display */ Widget shell, canvas; /* toplevel widget; child */ Window window; /* child widget's window */ XtAppContext app_con; /* application context */ int handle, i; char *bg_colorname = "white"; /* take background color from command line */ for (i = 0; i < argc - 1; i++) if (strcmp (argv[i], "-bg") == 0) bg_colorname = argv[i + 1]; /* create toplevel shell widget */ shell = XtAppInitialize (&app_con, (String)"Example", /* app class */ NULL, /* options */ (Cardinal)0, /* num of options */ &argc, /* command line */ argv, /* command line */ default_resources, NULL, /* ArgList */ (Cardinal)0 /* num of Args */ ); /* set default widget parameters (including window size) */ XtAppSetFallbackResources (app_con, default_resources); /* map actions to subroutines */ XtAppAddActions (app_con, actions, XtNumber (actions)); /* create canvas widget as child of shell widget; realize both */ XtSetArg(wargs[0], XtNargc, argc); XtSetArg(wargs[1], XtNargv, argv); canvas = XtCreateManagedWidget ((String)"", coreWidgetClass, shell, wargs, (Cardinal)2); XtRealizeWidget (shell); /* for the canvas widget, map events to actions */ XtSetArg (wargs[0], XtNtranslations, XtParseTranslationTable (translations)); XtSetValues (canvas, wargs, (Cardinal)1); /* initialize GNU libplot */ display = XtDisplay (canvas); pl_parampl ("XDRAWABLE_DISPLAY", display); window = XtWindow (canvas); pl_parampl ("XDRAWABLE_DRAWABLE1", &window); pl_parampl ("BG_COLOR", bg_colorname); handle = pl_newpl ("Xdrawable", NULL, NULL, stderr); pl_selectpl (handle); pl_openpl (); pl_fspace (0.0, 0.0, 1000.0, 1000.0); pl_flinewidth (0.25); /* transfer control to X Toolkit event loop (doesn't return) */ XtAppMainLoop (app_con); return 1; }
Even if you are not familiar with X Window System programming, the
structure of this application should be clear. It defines three
callbacks: Redraw
, Toggle
, and Quit
. They are
invoked respectively in response to (1) a window expose event or
mouse click, (2) a mouse click, and (3) a typed `q'.
The first drawing of the `C' curve (in red) takes place because
the window receives an initial expose event.
This example could be extended to take window resizing into account. Actually, X Drawable Plotters are usually used to draw vector graphics in off-screen pixmaps rather than on-screen windows. Pixmaps, unlike windows, are never resized.
libplotter
Plotter
class
The C++ binding for libplot
is provided by a class library, named
libplotter
. This library implements a Plotter
class,
of which all Plotters are instances. Actually, a Plotter would
normally be an instance of an appropriate derived class, determined by
the Plotter's output format. Derived classes currently include
XPlotter
, XDrawablePlotter
, PNMPlotter
,
GIFPlotter
, AIPlotter
, PSPlotter
,
FigPlotter
, PCLPlotter
, HPGLPlotter
,
TekPlotter
, and MetaPlotter
. The names should be
self-explanatory. The operations that may be applied to any Plotter
(e.g., the openpl
operation, which begins a page of graphics) are
implemented as public function members of the Plotter
class.
At the time a Plotter is created, its input, output, and error streams
must be specified. (The first is ignored, since at present, all
Plotters are write-only.) The streams may be specified either as
iostreams or as FILE
pointers. That is, the two constructors
Plotter(istream& instream, ostream& outstream, ostream& errstream); Plotter(FILE *infile, FILE *outfile, FILE *errfile);
are provided for the base Plotter class, and similarly for each of its derived classes. So, for example, both
PSPlotter plotter(cin, cout, cerr);
and
PSPlotter plotter(stdin, stdout, stderr);
are possible declarations of a Postscript Plotter that writes to
standard output. In the iostream case, an ostream with a null stream
buffer may be specified as the output stream and/or the error stream, to
request that no output take place. In the FILE
pointer case,
specifying a null FILE
pointer would accomplish the same thing.
Instances of the XPlotter
and XDrawablePlotter
classes
always ignore the output stream argument, since they write graphics to
an X Display rather than to a stream.
The parameter-setting function parampl
, which plays an important
role in all bindings of libplot
, is implemented in
libplotter
as a static function member of the Plotter
class. The following is a formal description.
char *
, i.e., a string. Unrecognized parameters are
ignored. For a list of the recognized parameters and their meaning, see
section Device driver parameters.
Just as in the C binding, Plotter::parampl
gives the programmer
fine control over the parameters of subsequently created Plotters. The
parameter values used by any Plotter are constant over the lifetime of
the Plotter, and are those that were set when the Plotter was created.
If at Plotter creation time a parameter is not set, its
default value will be used, unless the parameter is string-valued and
there is an environment variable of the same name, in which case the
value of that environment variable will be used.
Once set, a parameter may be unset by the programmer by calling
Plotter::parampl
with a value argument of NULL. This further
increases flexibility.
The source code for a graphics application written in C++, if it is to
use libplotter
, must contain the line
#include <plotter.h>
The header file plotter.h
is distributed with libplotter
,
and should have been installed on your system where your C++
compiler will find it. It declares the Plotter
class and
its derived class, and also contains some miscellaneous definitions.
It includes the header files <iostream.h>
and
<stdio.h>
, so you do not need to include them separately.
To link your application with libplotter
, you would use the
appropriate `-l' option(s) on the command line when compiling it.
You would use
-lplotter -lXaw -lXmu -lXt -lXext -lX11 -lm
or, in recent releases of the X Window System,
-lplotter -lXaw -lXmu -lXt -lSM -lICE -lXext -lX11 -lm
(Alternatively, you may need to use `-lplotter -lXm -lXt -lXext -lX11 -lm', `-lplotter -lXm -lXt -lXext -lX11 -lm -lc -lgen', or `-lplotter -lXm -lXt -lXext -lX11 -lm -lc -lPW', on systems that provide Motif widgets instead of Athena widgets. In recent releases of the X Window System, you would insert `-lSM -lICE'. Recent releases of Motif require `-lXp' as well.)
On some platforms, the directories in which libplotter
or the
other libraries are stored must be specified on the command line.
For example, the options `-lXaw -lXmu -lXt -lSM -lICE -lXext
-lX11', which specify X Window System libraries, may need to be
preceded by an option like `-L/usr/X11/lib'.
On most systems libplotter
is installed as a DLL (dynamically
linked library, or `shared' library). This means that the linking with
your application will take place at run time rather than compile time.
The environment variable LD_LIBRARY_PATH
lists the directories
which will be searched for DLL's at run time. For your application to
be executable, this environment variable should include the directory in
which libplotter
is stored.
In a previous section, there are several sample C programs that show
how to draw vector graphics using libplot
's C binding.
See section Sample drawings in C. In this section, we give a modified
version of one of the C programs, showing how libplot
's C++
binding, i.e., libplotter
, can be used similarly.
The following C++ program draws an intricate and beautiful path (Bill Gosper's "C" curve).
#include <plotter.h> #define MAXORDER 12 void draw_c_curve (Plotter& plotter, double dx, double dy, int order) { if (order >= MAXORDER) plotter.fcontrel (dx, dy); // continue path along (dx, dy) else { draw_c_curve (plotter, 0.5 * (dx - dy), 0.5 * (dx + dy), order + 1); draw_c_curve (plotter, 0.5 * (dx + dy), 0.5 * (dy - dx), order + 1); } } int main () { // set a Plotter parameter Plotter::parampl ("PAGESIZE", "letter"); PSPlotter plotter(cin, cout, cerr); // declare Plotter if (plotter.openpl () < 0) // open Plotter { cerr << "Couldn't open Plotter\n"; return 1; } plotter.fspace (0.0, 0.0, 1000.0, 1000.0); // specify user coor system plotter.flinewidth (0.25); // line thickness in user coordinates plotter.pencolorname ("red"); // path will be drawn in red plotter.erase (); // erase Plotter's graphics display plotter.fmove (600.0, 300.0); // position the graphics cursor draw_c_curve (plotter, 0.0, 400.0, 0); if (plotter.closepl () < 0) // close Plotter { cerr << "Couldn't close Plotter\n"; return 1; } return 0; }
The above is a straightforward translation of the corresponding C
program. Here, plotter
is declared as an instance of the
PSPlotter
class, which will write Postscript graphics to the
output stream cout
. The graphics are drawn by invoking member
functions.
This object-oriented approach to drawing graphics is probably more
natural than the approach used by the C binding. With
libplotter
, the use of multiple Plotters in an application
becomes very easy. No switching between Plotters is required: the
graphics operations can be immediately invoked on any existing Plotter.
libplot
: A detailed listing
In the current release of GNU libplot
, any Plotter supports 92
distinct operations. A language binding for libplot
necessarily includes 92 functions that correspond to these operations.
In the C binding, these 92 functions belong to the C API
(application programming interface). In the C++ binding, they are
implemented as public member functions of the Plotter
class.
A language binding may also include functions for creating,
selecting, and deleting Plotters. For example, the C binding
includes the additional functions pl_newpl
, pl_selectpl
,
and pl_deletepl
. See section The C application programming interface. In the C binding, the names
of all functions should be preceded by "pl_" unless the header file
plotcompat.h
is included. See section C compiling and linking.
The 92 functions that operate on a specified Plotter are divided into the four sets tabulated below.
Many functions come in two versions: integer and double precision
floating point. Internally, libplot
uses double precision
floating point. The integer versions are provided for backward
compatibility. If there are two versions of a function, the name of
the floating point version begins with the letter `f'.
Many functions come in both absolute and relative versions, also. The latter use relative coordinates (i.e., coordinates relative to the current position of the graphics cursor), and their names end in `rel'.
Currently, only a few of the 92 functions have meaningful return values.
The following are the "setup functions" in libplot
. They are
the basic functions that open, initialize, or close an already-created
Plotter. They are listed in the approximate order in which they would
be called.
In the C binding, the names of all functions should be preceded by
"pl_", unless the header file plotcompat.h
is included. See section C compiling and linking. In the C++ binding, these are member
functions of the Plotter
class and its subclasses.
openpl
. Future releases may support window re-use.
openpl
...closepl
pair remain on the graphics display
even after a new page is begun by a subsequent invocation of
openpl
. Currently, only X Drawable Plotters and Tektronix
Plotters are persistent. Future releases may support optional
persistence for X Plotters also.
On X Plotters and X Drawable Plotters the effects of invoking erase
will be altogether different if the device driver parameter
USE_DOUBLE_BUFFERING
is set to "yes". In this case, objects
will be written to an off-screen buffer rather than to the graphics
display, and invoking erase will (1) copy the contents of this
buffer to the display, and (2) erase the buffer by filling it with
the background color. This `double buffering' feature facilitates
smooth animation. See section Device driver parameters.
plot
.
libplot
, some Plotters output pages in
real time, i.e., with each invocation of closepl. This is true of
PCL and HP-GL Plotters, for example. Similarly, Plotters that normally
output only a single page (PNM, GIF, Illustrator, and Fig Plotters) do
so immediately after that page is ended. However, Postscript Plotters
do not output their page(s) of graphics until they are deleted.
The following are the "drawing functions" in libplot
. When
invoked on a Plotter, these functions cause it to draw objects (paths,
circles, ellipses, points, markers, and text strings) on the associated
graphics display. A path is a sequence of line segments, arc
segments (either circular or elliptic), and/or Bezier curve segments
(either quadratic or cubic). Paths are drawn incrementally, one segment
at a time.
In the C binding, the names of all functions should be preceded by
"pl_", unless the header file plotcompat.h
is included. See section C compiling and linking. In the C++ binding, these are member
functions of the Plotter
class and its subclasses.
textangle
has
been called.
arc
and farc
,
but use cursor-relative coordinates.
p0
=(x0, y0) and end p2
=(x2, y2) of
a quadratic Bezier curve, and its intermediate control point
p1
=(x1, y1). If the graphics cursor is at
p0
and a path is under construction, then the curve is added to
the path. Otherwise the current path (if any) is ended, and the
curve begins a new path. In all cases the graphics cursor is moved
to p2
. bezier2rel and fbezier2rel are similar to
bezier2
and fbezier2
, but use cursor-relative coordinates.
The quadratic Bezier curve is tangent at p0
to the line segment
joining p0
to p1
, and is tangent at p2
to
the line segment joining p1
to p2
. So it fits
snugly into a triangle with vertices p0
, p1
, and
p2
.
When using a PCL Plotter to draw Bezier curves on a LaserJet III, you
should set the parameter PCL_BEZIERS
to "no". That is because
the LaserJet III, which was Hewlett--Packard's first PCL 5 printer,
does not recognize the Bezier instructions supported by later PCL 5
printers. See section Device driver parameters.
p0
=(x0, y0) and end p3
=(x3,
y3) of a cubic Bezier curve, and its intermediate control points
p1
=(x1, y1) and p2
=(x2, y2).
If the graphics cursor is at p0
and a path is under
construction, then the curve is added to the path. Otherwise the
current path (if any) is ended, and the curve begins a new path.
In all cases the graphics cursor is moved to p3
.
bezier3rel and fbezier3rel are similar to bezier3
and
fbezier3
, but use cursor-relative coordinates.
The cubic Bezier curve is tangent at p0
to the line segment
joining p0
to p1
, and is tangent at p3
to
the line segment joining p2
to p3
. So it fits
snugly into a quadrangle with vertices p0
, p1
, p2
,
and p3
.
When using a PCL Plotter to draw Bezier curves on a LaserJet III, you
should set the parameter PCL_BEZIERS
to "no". That is because
the LaserJet III, which was Hewlett--Packard's first PCL 5 printer,
does not recognize the Bezier instructions supported by later PCL 5
printers. See section Device driver parameters.
pc
=(xc,yc), p0
=(x0,y0), and
p1
=(x1,y1) that define a so-called quarter ellipse.
This is an elliptic arc from p0
to p1
with center
pc
. If the graphics cursor is at point p0
and a path
is under construction, the quarter-ellipse is added to it. Otherwise
the path under construction (if any) is ended, and the
quarter-ellipse begins a new path. In all cases the graphics cursor
is moved to p1
.
The quarter-ellipse is an affinely transformed version of a quarter
circle. It is drawn so as to have control points p0
,
p1
, and p0
+p1
-pc
. This means that it
is tangent at p0
to the line segment joining p0
to
p0
+p1
-pc
, and is tangent at p1
to the
line segment joining p1
to p0
+p1
-pc
.
So it fits snugly into a triangle with these three control points as
vertices. Notice that the third control point is the reflection of
pc
through the line joining p0
and p1
.
ellarcrel and fellarcrel are similar to ellarc and
fellarc, but use cursor-relative coordinates.
The following are the "attribute functions" in libplot
. When
invoked on a Plotter, these functions set its drawing attributes, or
save them or restore them. Path-related attributes include graphics
cursor position, pen color, fill color, fill rule, line thickness, line
style, cap style, join style, and miter limit. Text-related attributes
include pen color, font name, font size, and text angle.
Setting any path-related drawing attribute automatically terminates the
path under construction (if any), as if the endpath
operation had been invoked.
In the C binding, the names of all functions should be preceded by
"pl_", unless the header file plotcompat.h
is included. See section C compiling and linking. In the C++ binding, these are member
functions of the Plotter
class and its subclasses.
HPGL_VERSION
is set to
a value less than "2" (the default). See section Device driver parameters.
xfig
itself does not support it. Also, HPGL Plotters do not
support it if HPGL_VERSION
is set to a value less than "2" (the
default). See section Device driver parameters.
The LaserJet III, which was Hewlett--Packard's first PCL 5 printer,
did not support the nonzero-winding fill rule. However, all later
PCL 5 printers from Hewlett--Packard support it.
HPGL_VERSION
is
equal to "1.5" or "2" (the default). (If the version is "1"
then only circles and rectangles aligned with the coordinate axes may be
filled.) Opaque filling, including white filling, is supported
only if the parameter HPGL_VERSION
is "2" and the parameter
HPGL_OPAQUE_MODE
is "yes" (the default). See section Device driver parameters.
HPGL_VERSION
is set to a value less than "2" (the default).
See section Device driver parameters.
HPGL_VERSION
is set to
a value less than "2" (the default). See section Device driver parameters.
HPGL_VERSION
is less
than "2" (the default; see section Device driver parameters).
Warning: If the map from the user coordinate system to the
device coordinate system is not uniform, each dash in a dashed path
should ideally be drawn on the graphics display with a length that
depends on its direction. But currently, only Postscript Plotters do
this. Other Plotters always draw any specified dash with the same
length, irrespective of its direction. The length that is used is the
minimum length, in the device coordinate system, that can correspond to
the specified dash length in the user coordinate system.
"solid" -------------------------------- "dotted" - - - - - - - - "dotdashed" ---- - ---- - ---- - "shortdashed" ---- ---- ---- ---- "longdashed" ------- ------- ------- "dotdotdashed" ---- - - ---- - - "dotdotdotdashed" ---- - - - ---- - - -In the preceding patterns, each hyphen stands for one line thickness. This is the case for sufficiently thick lines, at least. So for sufficiently thick lines, the distance over which a dash pattern repeats is scaled proportionately to the line thickness. The "disconnected" line style is special. A "disconnected" path is rendered as a set of filled circles, each of which has diameter equal to the nominal line thickness. One of these circles is centered on each of the juncture points of the path (i.e., the endpoints of the line segments or arcs from which it is constructed). Circles and ellipses with "disconnected" line style are invisible. Disconnected paths, circles, and ellipses are not filled. All line styles are supported by all Plotters, with the following exceptions. HP-GL Plotters do not support the "dotdotdotdashed" style unless the parameter
HPGL_VERSION
is set to "2" (the default).
Tektronix Plotters do not support the "dotdotdotdashed" style, and do
not support the "dotdotdashed" style unless the parameter TERM
is
set to "kermit". See section Device driver parameters.
idraw
and xfig
treat
zero-thickness lines as invisible. So when producing editable
graphics with a Postscript or Fig Plotter, using a zero line thickness
may not be desirable.
Tektronix Plotters do not support drawing with other than a default
thickness, and HP-GL Plotters do not support doing so if the parameter
HPGL_VERSION
is set to a value less than "2" (the default;
see section Device driver parameters).
Warning: If the map from the user coordinate system to the
device coordinate system is not uniform, each line segment in a
polygonal path should ideally be drawn on the graphics display with a
thickness that depends on its direction. But currently, only Postscript
Plotters do this. Other Plotters draw all line segments in a path
with the same thickness. The thickness that is used is the minimum
thickness, in the device coordinate system, that can correspond to the
thickness of the path in the user coordinate system.
HPGL_VERSION
is "2" (the default), and the value of
the parameter HPGL_OPAQUE_MODE
is "yes" (the default).
See section Device driver parameters.
HPGL_VERSION
is "2" (the default) and the value of
the parameter HPGL_OPAQUE_MODE
is "yes" (the default).
See section Device driver parameters.
libplot
's drawing attributes, which are set by the attribute
functions documented in this section. So popping off the graphics
context restores the drawing attributes to values they previously had.
A path under construction is regarded as part of the graphics
context. For this reason, calling restorestate automatically calls
endpath to terminate the path under construction, if any. All
graphics contexts on the stack are popped off when closepl
is
called, as if restorestate
had been called repeatedly.
libplot
's drawing attributes, which are set by the attribute
functions documented in this section. A path under construction,
if any, is regarded as part of the graphics context. That is
because paths may be drawn incrementally, one line segment or arc at a
time. When a graphics context is returned to, the path under
construction may be continued.
The following are the "mapping functions" in libplot
. When
invoked on a Plotter, these functions affect the affine transformation
it employs for mapping from the user coordinate system to the device
coordinate system. They may be viewed as performing transformations of
the user coordinate system. Their names resemble those of the
corresponding functions in the Postscript language. For information on
how to use them to draw graphics efficiently, consult any good book on
Postscript programming, or the Postscript Language Reference
Manual.
In the C binding, the names of all functions should be preceded by
"pl_", unless the header file plotcompat.h
is included. See section C compiling and linking. In the C++ binding, these are member
functions of the Plotter
class and its subclasses.
In designing the libplot
library, every effort was made to make
the Plotter interface independent of the type of Plotter. To the
extent that device dependence exists, it is captured by a manageable
number of device driver parameters.
In the C binding, a value for any parameter may be specified by
calling the pl_parampl
function. The pl_parampl
function
does not operate on any particular Plotter: it belongs to the C
binding as a whole. The parameter values used by any Plotter are
constant over the lifetime of the Plotter, and are those that were in
effect when the Plotter was created. Each driver parameter has a value
that is allowed to be a generic pointer (a void *
). For most
parameters, this value should be a string (a char *
).
pl_parampl
may be called any number of times. A parameter
may be unset by calling pl_parampl
with a value argument of
NULL.
If at Plotter creation time a parameter is not set, its default value will be used, unless the parameter is string-valued and there is an environment variable of the same name, in which case the value of that environment variable will be used. This rule increases run-time flexibility: an application programmer may allow non-critical driver parameters to be specified by the user via environment variables.
In the C++ binding, the function Plotter::parampl
is the analogue
of pl_parampl
. It is a static member of the Plotter
class and its subclasses. Like pl_parampl
, it does not act
on any particular Plotter: rather, it sets the parameters of
subsequently created Plotters.
The following are the currently recognized parameters (unrecognized ones
are ignored). The most important ones are DISPLAY
, which affects
X Plotters, BITMAPSIZE
, which affects X Plotters, PNM
Plotters, and GIF Plotters, and PAGESIZE
, which affects
Illustrator, Postscript, Fig, and HP-GL Plotters. These three
parameters are listed first and the others alphabetically. Many of the
parameters, such as the several whose names begin with "HPGL", affect
only a single type of Plotter.
DISPLAY
BITMAPSIZE
Xplot.geometry
. This is for backward compatibility.
PAGESIZE
xfig
display. For PCL and HP-GL
Plotters, the graphics display will be a square region of the same size,
but may be positioned differently. For PCL Plotters, fine control over
its positioning on the page may be accomplished by setting the
PCL_XOFFSET
and PCL_YOFFSET
parameters. For HP-GL
Plotters, HPGL_XOFFSET
and HPGL_YOFFSET
are used
similarly.
BG_COLOR
erase
is
invoked). The background color may be changed at any later time by
invoking the bgcolor (or bgcolorname) and erase operations.
An unrecognized color name sets the background color to the default.
For information on what names are recognized, see section Specifying Colors by Name.
GIF_ANIMATION
erase
operation will have special semantics: with the exception
of its first invocation, it will act as a separator between successive
images in the written-out pseudo-GIF file. "no" means that
erase
should act as it does on other Plotters that do not write
graphics in real time, i.e., it should erase the image under
construction by filling it with the background color. If "no" is
specified, the pseudo-GIF file will contain only a single image.
GIF_DELAY
GIF_ITERATIONS
HPGL_ASSIGN_COLORS
HPGL_VERSION
is "2". "no" means to draw with a fixed
set of pens, specified by setting the HPGL_PENS
parameter. "yes"
means that pen colors will not restricted to the palette specified in
HPGL_PENS
: colors will be assigned to "logical pens" in the
range #1...#31, as needed. Other than color LaserJet printers
and DesignJet plotters, not many HP-GL/2 devices allow the assignment of
colors to logical pens. So this parameter should be used with
caution.
HPGL_OPAQUE_MODE
HPGL_VERSION
is "2". "yes" means that the HP-GL/2 output
device should be switched into opaque mode, rather than transparent
mode. This allows objects to be filled with opaque white and other
opaque colors. It also allows the drawing of visible white lines,
which by convention are drawn with pen #0. Not all HP-GL/2 devices
support opaque mode or the use of pen #0 to draw visible white
lines. In particular, HP-GL/2 pen plotters do not. Some older
HP-GL/2 devices reportedly malfunction if asked to switch into opaque
mode. If the output of an HP-GL Plotter is to be sent to such a
device, a "no" value is recommended.
HPGL_PENS
HPGL_VERSION
is "1.5" or "2" and "1=black" if the
value of HPGL_VERSION
is "1". Relevant only to HP-GL
Plotters. The set of available pens; the format should be
self-explanatory. The color for any pen in the range #1...#31 may
be specified. For information on what color names are recognized, see
section Specifying Colors by Name. Pen #1 must always be present, though it need
not be black. Any other pen in the range #1...#31 may be omitted.
HPGL_ROTATE
HPGL_VERSION
is "2".
HPGL_VERSION
HPGL_XOFFSET, HPGL_YOFFSET
INTERLACE
MAX_LINE_LENGTH
META_PORTABLE
PCL_ASSIGN_COLORS
PCL_BEZIERS
PCL_ROTATE
PCL_XOFFSET, PCL_YOFFSET
PNM_PORTABLE
TERM
xterm
. Before drawing graphics, a Tektronix
Plotter will emit an escape sequence that causes the terminal emulator's
auxiliary Tektronix window, which is normally hidden, to pop up.
After the graphics are drawn, an escape sequence that returns control to
the original VT100 window will be emitted. The Tektronix window will
remain on the screen.
If the value is "kermit", "ansi.sys", "ansissys", "ansi.sysk", or
"ansisysk", it is taken as a sign that the current application is
running in the VT100 terminal emulator provided by the MS-DOS version of
kermit
. Before drawing graphics, a Tektronix Plotter will emit
an escape sequence that switches the terminal emulator to Tektronix
mode. Also, some of the Tektronix control codes emitted by the Plotter
will be kermit
-specific. There will be a limited amount of color
support, which is not normally the case (the 16 ansi.sys
colors
will be supported). The "dotdotdashed" line style will be supported,
which is also not normally the case. After drawing graphics, the
Plotter will emit an escape sequence that returns the emulator to VT100
mode. The key sequence `ALT minus' may be employed manually within
kermit
to switch between the two modes.
TRANSPARENT_COLOR
TRANSPARENT_COLOR
is set and an animated pseudo-GIF file is
produced, the `restore to background' disposal method will be used for
each image in the file. Otherwise, the `unspecified' disposal method
will be used.
USE_DOUBLE_BUFFERING
VANISH_ON_DELETE
XDRAWABLE_COLORMAP
Colormap *
, a pointer to a
colormap from which colors should be allocated. NULL indicates that the
colormap to be used should be the default colormap of the default screen
of the X display.
XDRAWABLE_DISPLAY
Display *
, a pointer to the X display with
which the drawable(s) to be drawn in are associated.
XDRAWABLE_DRAWABLE1
XDRAWABLE_DRAWABLE2
Drawable *
, a
pointer to a drawable to be drawn in. A `drawable' is either a
window or a pixmap. At the time an X Drawable Plotter is created,
at least one of the two parameters must be set.
X Drawable Plotters support simultaneous drawing in two drawables
because it is often useful to be able to draw graphics simultaneously in
both an X window and its background pixmap. If two drawables are
specified, they must have the same dimensions and depth, and be
associated with the same screen of the X display.
@ifnottex The following appendices contain miscellaneous information on the GNU plotting utilities.
Go to the first, previous, next, last section, table of contents.