NAME filter programming - writing code for graphics
filters
WRITING A GRAPHICS FILTER
In order to use C-PLOT with an unsupported
graphics device, you will need to write some device-dependent
code. All you have to do is supply the following functions and
link your code with the module driver.o supplied with this
package.
Almost all drawing, including text, is done by plotting
lines. For drawing symbols as dots, a point routine is needed.
For circular symbols (empty and filled), a circle routine is
needed. The circle routine may also make use of a window (or
clipping) routine to prevent circles near the edge of the plot
from extending outside the axes.
For raster devices, such as dot matrix printers and memory-
mapped displays, complete incremental line and circle drawing
routines are available.
The arguments to all functions are integers.
openpl() - This routine is called before
any plotting instructions are issued. Its sends mode-changing
strings, clears buffers, opens temporary files or does whatever
is needed to prepare the device for graphics. It must return a
value of 0 if the open is successful. If, for instance, hardware
is unavailable, the routine should return non-zero. This
function will not be called again until after a
closepl().
closepl(flag) - This
routine should restore the device to text mode, send out the
image to the printer or do whatever is necessary when the plot is
complete. The argument
flag is normally 0.
It is nonzero when the filter is terminated abnormally (if the
user hits ^C, for example, or if a termination
signal was sent to the filter from another process).
dspage() - This routine is called
when it is time to update the display. For instance, if the
filter is using buffered output to a terminal, the buffer should
be flushed. For many filters (all spooling filters, for
example), this routine can do nothing.
sel_pen(x) - Although
not required, you can provide a routine by this name. Its
purpose is to select a line width or color on certain devices.
The parameter
x will either be zero or a
positive integer and is simply the pen number a user gives as
part of a p or z plotting command. You
could interpret the parameter in any way. However, it is
recommended you follow the conventions stated in the section that
follows. If you don't provide a routine by this name, a dummy
version will be loaded from libfilter.a.
erase() - This routine may erase the
screen, clear raster buffers or do nothing, if that is
appropriate.
space(x0,
y0, x1,
y1) - This routine sets up the scaling
points for all subsequent drawing commands. The first two
parameters are the coordinates of the lower left-hand corner.
The second two are the coordinates of the upper right-hand
corner. These coordinates should map to the entire available
area of the device. All drawing command coordinates will lie
within the region defined by these two points
point(x0,
y0) - This routine is called to plot a
point.
line(x0,
y0, x1,
y1) - This routine should draw a line
between the points given by the two pairs of coordinates. It is
not necessary to do any clipping as the endpoints are guaranteed
to lie within the display area set up with
space().
window(x0,
y0, x1,
y1) - This routine defines a clipping
window. The first pair of arguments are the coordinates of the
lower left-hand corner and the second pair are those for the
upper right-hand corner. The clipping window is only required
when drawing circles, and the only circles that are drawn are
those used for circular plotting symbols. If you don't provide a
window() routine, a do-nothing version will be
loaded from libfilter.a.
circle(x0,
y0, radius) - This
function is called to draw a circle of radius
radius with center at x0,
y0. The circle should be clipped according
to the current window. This routine is only called for plotting
circular symbols. If the center of the circle is outside of the
plotting window, this routine will not be called. If
implementing a clipping window is too difficult, the result will
be no worse than circular symbols overlapping the plot axes.
beg_sym(n) and
end_sym() - These routines make it possible to
replace the default grid fills for the solid symbols with device-
dependent circle- and polygon-fill routines. When drawing points
using one of C-PLOT's numbered special symbols,
beg_sym() is called for each data point before any
calls to point(), line() or
circle(). The low byte of the argument
n is one plus the symbol code as entered
using the sy command. When the symbol is a black-
filled symbol, the corresponding white-filled symbol outline is
sent first, with 0x100 added to n to indicate
the symbol is to be filled with black. When the lines for the
grid fill are sent, beg_sym() is called again with
0x200 added to n. The routine
end_sym() is called after all the function calls to
point(), line() and
circle() required to draw each symbol have been
made. Do-nothing versions of these two routines will be loaded
from libfilter.a if they are not present in the source
module you provide.
USING EXISTING Plot(5) ROUTINES
C-PLOT requirements differ in some places
from the standard UNIX plot(5) function descriptions. In
particular, the C-PLOT space()
routine sets up a scaling region that encompasses the entire
usable plotting area while the standard UNIX routine sets up a
region that is the largest square that can fit on the device.
Another difference is that some UNIX closepl()
routines do not return the device to text mode. C-
PLOT routines do.
In order to make it possible to use existing UNIX device-
dependent plot libraries with C-PLOT, you can
intercept the calls to several standard routines, adjust the
arguments or execute some other code, before turning control over
to them. The C-PLOT filter driver routines
actually make the following function calls
xopenpl(), xclosepl(),
xspace(), xerase(),
xpoint(), xline(), and
xcircle() instead of the names given above.
Normally, routines from libfilter.a are loaded that simply
call routines by the x-less names.
The code shown here is an example of the interception trick
that can be used to fix the problem with the scaling areas:
| -
xspace(x0, y0, x1, y1) {
long x;
x = x1 * 3L / 4L;
space(x0, y0, (int) x, y1);
}
|
|
Here, a parameter provided to the UNIX library routine is
rescaled so subsequent drawing commands will fill the entire
screen.
This second example returns the device to text mode after
calling the standard routine.
| -
xclosepl(mode) {
closepl();
/* Send sequence to reset text mode on this device */
write(1, "\033[0g", 4);
}
|
|
The file g_proto.c in the filters subdirectory
of the standard C-PLOT distribution has sample
code that can be used to adapt existing plot(5) libraries
to a C-PLOT filter.
SUBROUTINES IN libfilter.a
The following subroutines are tools to simplify writing
filters. The first five routines interface to very fast and
efficient code that buffers output written to the standard output
(file descriptor 1).
binit() - Call this routine to
initialize or reinitialize the internal buffer pointers.
bputch(c) - Adds the
low eight bits of the integer
c to the output
queue.
bputwd(i) - Adds
i as a short integer to the output queue,
high byte first.
bputstr(s) - Adds the
null-terminated string
s to the output queue.
bwrite(p,
n) - Adds
n bytes of
the data pointed to by the character pointer
p to the output queue.
bflush() - Writes out any pending
data in the queue.
These next routines are used with raster filters when you are
not using the functions provided by raster.o. The first
routine draws lines and the second circles. For both, the
arguments must be already scaled to device units.
_line(Ox1,
y1, x2,
y2) - This routine draws raster lines. You
must provide the following three routines, which are called by
_line(), to set pixels on the device or in your
raster buffer: _hline(x1,
x2, y ) draws a
horizontal line from x1 to
x2 at y,
_vline(x,
y1, y2) draws a vertical
line from y1 to y2 at
x and
_ppoint(x,
y) draws a point at x and
y.
_circle(x,
y, r) - This routine
draws raster circles. You must assign values to the externally
defined integers
asx and asy if the
pixel aspect ratio is not one to one. You must also provide the
routine _ppoint(x,
y) which draws a point at
x and y.
window(x1,
y1, x2,
y2) - This routine is included with the
above circle routines and sets the clipping window they use.
The following routines provide simple general purpose
scaling.
space(x1,
y1, x2,
y2) - The coordinates are of the lower left
and upper right corners of the maximum plotting area. The
routine assigns values to the external variables
_px0, _py0, _pdx and
_pdy which are used in the following routines.
_mapx(x) - This routine
returns the value in device units for
x. You
must declare and initialize the integer _xmax to
contain the maximum value in device units for
x. (The minimum value is assumed to be
zero.) If you assign a nonzero value to the externally defined
integer revx, the sense of the x axis is
reversed. Make the assignment if the zero in device units for
the device is on the right side of its long axis.
_mapy(y) - This routine
returns the value in device units for
y. You
must declare and initialize the integer _ymax to
contain the maximum value in device units for
y. (The minimum value is assumed to be
zero.) If you assign a nonzero value to the externally defined
integer revy, the sense of the y axis is
reversed. Make the assignment if the zero in device units for
the device is on the top side of its short axis.
_mapr(r) - This routine
uses the value of
_xmax to provide a device-units
value for the radius used in the circle() routine.
DEVICE-INDEPENDNET STREAM
You could write a complete filter without using any of the
C-PLOT routines if you know the format of the
data stream from the plot program and a few other details.
The data stream consists of single character commands,
followed by zero to four parameters. The parameters are 16-bit
signed integers, sent in binary fashion, with the low-order byte
sent first.
The commands used are given in the following table.
| -
Command Parameters Function
c 3 Draw circle
e 0 Erase display
W 0 Erase window
l 4 Draw line
p 2 Draw point
s 4 Set scaling points
w 4 Set clipping window
x 0 Open routine
y 0 Unsynchronized close routine
z 1 Update-display routine
B 1 Begin symbol
E 0 End symbol
P 1 Select pen
Y 1 Synchronized close routine
Z 1 Synchronized close routine
q 0 Flush output
|
|
The synchronized close routine must send a
SIG_INT signal to the plot process when it has
finished processing the graphics instructions. The parameter to
the Y command is the process number (PID) of the
plot process as a short integer (now obsolete). The parameter to
the Z command is the process number (PID) of the
plot process as a long integer.
If the filter is invoked with an argument, by convention the
argument is the name of a file or device in which the filter
should put the device dependent output.
... Meeting the software needs of scientists since 1985 ...
Last Formatted Oct 29, 2000
Last Updated 09/13/95
Send comments, queries, suggestions to
info@certif.com
© 1995-2000 Certified Scientific Software. All rights reserved
|
|