file: PLOT G. Moody 7 August 1990 The UNIX plot(3) library is used by the `dbplot' application in this directory. This library is generally used by compiling with `-lplot' and then piping the device-independent output of the application into a UNIX plot(1) interpreter for the specific device. Alternatively, the application may be compiled using a device-specific plot(3) library (traditionally named libtxxx.a, where `xxx' is in some way related to the device name); in this case, the standard output of the application can be sent directly to the device. The plot(3) library and its interpreters have been available at least since Version 6 UNIX, and are a standard part of most if not all Berkeley-derived versions. The Adobe TranScript software includes a plot interpreter for PostScript devices. Certain USG (System V) distributions do not include `plot', however, and many systems lack plot interpreters for any but obsolete devices. It is quite simple to write your own plot library for a device of your choice, if you already know how to perform a few low-level graphics operations. For `dbplot', you will need to implement the following functions: void openpl(void) This function must perform any operations needed to initialize `graphics mode' for your output device. A properly implemented plot application must invoke `openpl' before using any of the other plot functions listed below. void closepl(void) This function should restore `normal mode' for your output device. A proper implementation of `closepl' should allow the application to switch back to graphics mode with another invocation of `openpl'. void erase(void) This function should erase the current plot. On a hardcopy device, this function should eject the current page and load a new one. void space(int left, int bottom, int right, int top) This function should define a virtual coordinate system for the output device. It should be invoked before using any of the other plot functions listed below. A typical implementation will look like this: #define XLEFT 0 /* device coordinate of leftmost pixel */ #define XRIGHT 511 /* device coordinate of rightmost pixel */ #define YBOTTOM 479 /* device coordinate of lowest pixel */ #define YTOP 0 /* device coordinate of highest pixel */ double x_scale, y_scale; int x_offset, y_offset; void space(int left, int bottom, int right, int top) { if (left == right || bottom == top) { printf("space: illegal arguments %d, %d, %d, %d\n", left, bottom, right, top); exit(1); } x_scale = (XRIGHT - XLEFT)/((double)(right - left)); y_scale = (YTOP - YBOTTOM)/((double)(top - bottom)); x_offset = left; y_offset = bottom; } Thus, for example, the statement: space(0, -500, 100, 500); has the effect of defining a virtual coordinate system in which the lower left corner is (0, -500), and the upper right corner is (100, 500). Arguments to other plot(3) functions are presented in the virtual coordinate system defined by `space'. Given the implementation above, these functions should transform the virtual coordinates to device coordinates by: x_device = (x_virtual - x_offset) * x_scale + XLEFT; y_device = (y_virtual - y_offset) * y_scale + YBOTTOM; so that, for example, (50, 0) in virtual coordinates is transformed into (255, 239) in device coordinates, given the examples above. The implementation above handles inverted coordinate systems (as shown in the example) gracefully. Traditionally, XLEFT, XRIGHT, YBOTTOM, and YTOP are defined as the corners of the largest plottable square (and thus do not coincide with the corners of a rectangular output device), to make it easy to draw true circles. For `dbplot', you may use the actual device limits if you wish, in order to obtain the best resolution in its output. If an application invokes `space' more than once, the scaling and offset determined by the second and later invocations should not be influenced by the previous ones. Some existing implementations of `space' (notably in at least some versions of the Adobe TranScript package) are defective in this respect; if you find that dbplot's annotations appear in the wrong place, this is probably the cause of the problem. void move(int x_virtual, int y_virtual) For a device such as a pen plotter, this function positions the pen to the specified coordinates, without drawing anything (i.e., "pen up"). For other devices, it may simply update internal variables needed to keep track of the point from which drawing will begin. void point(int x_virtual, int y_virtual) This function plots a point at the specified coordinates, and leaves the "pen" at that point. void cont(int x_virtual, int y_virtual) This functions draws a line from the current "pen" position to the specified coordinates, and leaves the "pen" at (x_virtual, y_virtual). void line(int x_virtual_start, int y_virtual_start, int x_virtual_end, int y_virtual_end) This function draws a line between the indicated coordinates, and leaves the "pen" at (x_virtual_end, y_virtual_end). It may be implemented trivially as: void line(int x_virtual_start, int y_virtual_start, int x_virtual_end, int y_virtual_end) { move(x_virtual_start, y_virtual_start); cont(x_virtual_end, y_virtual_end); } void label(char *string) This function prints its null-terminated string argument, beginning at or near the current "pen" position. If the device permits, the first character in the string should be placed such that the lower left corner of its bounding box (exclusive of left bearing or descender, if any) lies at the initial "pen" position. A proper implementation of `label' should leave the "pen" in a position which will allow concatenation of printed strings by successive invocations of `label'. A properly implemented application will pass only spaces and printable characters in its string; the handling of tabs, newlines, and control characters is undefined. This subset of the plot(3) library is sufficient for `dbplot'. A complete plot library also includes these functions: void arc(int x_center, int y_center, int x_start, int y_start, int x_end, int y_end) This function draws an arc with the specified center between the specified points, and leaves the "pen" at (x_end, y_end). void circle(int x_center, int y_center, int radius) This function draws a circle with the specified center and radius. The final position of the "pen" is undefined (implementation-dependent). void linemod(char *style) This function sets the drawing style used by `cont', `line', `arc', and `circle'. The `style' should be one of: "solid" "dotted" "longdashed" "shortdashed" "dotdashed" Some devices do not support multiple line styles; for these, `linemod' should be a no-op.