HELP RC_GRAPHIC Aaron Sloman May 1990 Updated: Adrian Howard Nov 1992 LIB * RC_GRAPHIC This "Relative-Coordinates" Graphics library defines a collection of graphical procedures, including turtle graphics, i.e. drawing procedures relative to a current state represented as the location and heading of a "turtle" moving on the screen. These are easier to use than the basic X facilities described in HELP * Xpw and REF * XpwPixmap, * XpwGraphic mentioned below. TEACH * XTOOLKIT gives additional general information. LIB * RC_ROTATE_XY This extension to RC_GRAPHIC provides procedures for rotating the coordinate frame. LIB * RC_MOUSE This extension to RC_GRAPHIC provides procedures for using the mouse in the graphics window to draw pictures or for other purposes. LIB * RC_DRAWGRAPH A procedure for drawing a graph of a given function. This makes use of LIB RC_GRAPHIC LIB * RC_GRAPHPLOT, * RC_GRAPHPLOT2 These files extend the graph drawing facilities by providing a wider range of options. See TEACH * RC_GRAPHPLOT, HELP * RC_GRAPHPLOT LIB * RC_SET_SCALE A procedure for specifying the user coordinates in terms of inches, centimetres or frame height or width. LIB * RC_CLIP_REGION A procedure for setting the clipping limits relative to the current user coordinates. LIB * RC_CONTEXT A mechanism that makes it possible to switch between different windows by saving and restoring the variables associated with each window. CONTENTS - (Use g to access required sections) -- LIB * RC_GRAPHIC: Introductory remarks -- Example session -- Startup and re-start procedure -- rc_start() -- rc_wm_input (default -false-) -- Altering window size and location -- rc_window_xsize (default 500) -- rc_window_ysize (default 500) -- rc_window_x (default 520) -- rc_window_y (default 300) -- rc_window -- rc_new_window(width, height, xloc, yloc, setframe) -- rc_setsize() -- rc_clear_window() -- Setting or altering the coordinate frame relative to window -- rc_xorigin, rc_yorigin, rc_xscale, rc_yscale -- rc_set_coordinates(xorigin, yorigin, xscale, yscale) -- rc_shift_frame_by(x, y) -- rc_stretch_frame_by(scale) -- Drawing and jumping relative to current location and heading -- rc_xposition, rc_yposition, rc_heading -- rc_turn(angle) -- rc_jump(amount) -- rc_jumpby(dx, dy) -- rc_drawto(pointcoords) -- rc_drawby(dx, dy) -- rc_draw(amount) -- rc_point_here() -- rc_newposition(amount) -> newy -> newx -- rc_draw_rectangle(width, height) -- rc_draw_oblong(width, height, radius) -- rc_arc_around(radius, degrees) -- Absolute drawing and jumping -- rc_jumpto(pointcoords) -- rc_drawpoint(pointcoords) -- rc_drawline(pointcoords1, pointcoords2) -- rc_draw_arc(pointcoords, width, height, angle1, angleinc) -- Saving and restoring "turtle" state -- rc_save_state() -> state -- rc_restore_state(state) -- Transformations from and to user coordinates -- rc_transxyout(x_user, y_user) -> y_win -> x_win -- rc_transxyin(x_win, y_win) -> y_user -> x_user -- Using LIB * RC_ROTATE_XY to rotate user coordinate frame -- rc_frame_angle (active variable, current rotation angle) -- rc_rotate_frame(angle) -- rc_rotate_xy(user_x, user_y) -> window_y -> window_x -- Temporarily altering the user coordinate frame -- Printing strings in the window -- rc_print_at (pointcoords, string) -- rc_print_here(string) -- Clipping facilities used by rc_drawline -- rc_clipping (default true) -- rc_xmin rc_xmax rc_ymin rc_ymax -- LIB * RC_CLIP_REGION allows clipping relative to user coordinates -- rc_clip_region(REGION) -- rc_clip_region(XMIN, XMAX, YMIN, YMAX) -- Optional use of two numbers or point data-structure (pointcoords) -- rc_conspoint(x,y) -> point -- rc_destpoint(point) -> y -> x -- rc_getxy(pointcoords) -> y -> x -- The current window (rc_window) -- Drawing in multiple windows -- Coordinate transformations: rc_transxyin, rc_transxyout -- rc_xscale, rc_yscale, -- rc_xorigin, rc_yorigin; -- LIB * RC_SET_SCALE: setting scales in inches, cm, frame units -- rc_set_scale(type, xscale, yscale) -- rc_pixels_per_inch (default 90) -- LIB * RC_SET_COORD_FRAME can simplify setting scales and origins -- rc_set_coord_frame(TYPE, WINDOW_REGION, USER_REGION) -- Examples -- LIB * RC_DRAWGRAPH : graph drawing package -- USEFUL ADDITIONAL X FACILITIES -- Changing line drawing style -- Changing foreground/background colours -- Changing font -- LIB * RC_MOUSE - mouse interaction in the graphics window -- rc_mouse_draw(listpoints, stop_button) -- rc_rubber_function (integer) -- rc_transxyin(x_window, y_window ) -> y_user -> x_user ; -- rc_mouse_setup(widget) -- rc_mouse_disable(widget) -- rc_mousing (boolean, default false) -- rc_button_procedures (list, default []) -- rc_move_procedures (list, default []) -- rc_mouse_do(first_input, other_input, test_exit) -- Asynchronous mouse-button event handling -- LIB * RC_CONTEXT: USING SEVERAL WINDOWS AND SWITCHING BETWEEN THEM -- rc_context_vars: specifying the context variables -- The default rc_context_vars -- rc_context() -> context -- context -> rc_context() -- rc_destroy_context(context) -- Example of use of more than one window -- ADDITIONAL OPERATIONS ON GRAPHICS WINDOW -- INTERFACING TO A DIFFERENT WINDOW MANAGER -- See Also -- Acknowledgements -- LIB * RC_GRAPHIC: Introductory remarks ----------------------------- Working through TEACH * RC_GRAPHIC will make the following description easier to understand. The RC_GRAPHIC (Relative Coordinates Graphic) library package defines a collection of Pop-11 procedures for drawing pictures in a graphics window. It is intended to provide very easy mechanisms for getting started with the POPLOG X windows graphics facilities. There are several key ideas in the package, designed to make it easier to use than the basic X facilities. (1) The mechanisms for creating and clearing the graphics window are packaged up into simple procedures with convenient defaults. (2) The drawing primitives work on a coordinate frame defined by the user, rather than on window coordinates. (3) A convenient default coordinate frame is provided, with the origin in the middle of the window, and y-values going up the screen. (4) There are "turtle" graphical facilities for giving commands relative to a drawing state defined by a current location and a heading. Even a procedure for drawing circular arcs is available that uses the current location and heading to start drawing and after drawing the arc updates the turtle's location and heading. (5) Users can easily define a clipping boundary within the graphics window, and lines will then not be drawn outside this boundary. (6) The procedures that require points to be represented by two coordinates will all accept either two numbers or a point data-structure. (7) LIB * RC_ROTATE_XY, described below, provides an extension that makes it easy do deal with rotation of the user coordinate frame relative to the graphics window. (8) LIB * RC_DRAWGRAPH, described below, provides a graph-drawing procedure based on the above facilities, making it easy to produce a graph of a function from numbers to numbers within bounds specified by the user, and with axes marked as required by the user. (9) LIB * RC_MOUSE provides a mechanism for interacting with the mouse in the graphics window and obtaining coordinates relative to the user coordinate frame. More basic mechanisms on which these are defined can be seen in the files LIB * xt_widget, * xt_widgetinfo * XptNewWindow * XptArgList which are used as the basis for LIB RC_GRAPHIC. Further information on the more basic and general facilities can be found in HELP * Xpw and the files referred to there. LIB * RC_GRAPHIC is defined in such a way that the dependence on the X system is clearly indicated, and it should be fairly easy to port it to other graphical interfaces. See the section on interfacing to a different window manager, below. -- Example session ---------------------------------------------------- An example interactive session demonstrating most of the facilities is provided in the TEACH * RC_GRAPHIC file. The following sections describe the facilities in the rc_graphic library. -- Startup and re-start procedure ------------------------------------- -- rc_start() This starts up the graphics window, or if it has already been started, clears it. If -rc_window- is not a live window widget then a new window is created using the current values for size and location, namely rc_window_xsize, rc_window_ysize, rc_window_x, rc_window_y. The first time rc_start is invoked it also sets up a convenient user-coordinate frame with the origin in the middle of the window and puts the "turtle" at location 0,0 with heading 0 (i.e. facing right if the value for rc_xscale is positive). If the value of rc_yscale is negative then turn angles are counter clockwise. See the section on rc_mouse_setup, below. -- rc_wm_input (default -false-) This variable controls the value of the "XtR input" resource of the shell widget of the -rc_window- when a widget is created by -rc_start- or -rc_new_window-. If -true- the window manager will control when keyboard input is sent to -rc_window-. This is not important unless you are interested in X keyboard handling. -- Altering window size and location ---------------------------------- The default startup window size and location can be altered by the user by assigning integers to the following global variables before rc_start is first invoked. Window width and height in screen pixels -- rc_window_xsize (default 500) -- rc_window_ysize (default 500) Location of top left corner in screen coordinates -- rc_window_x (default 520) -- rc_window_y (default 300) If these variables are given different default values before the library is compiled, the library will not alter them. The current window widget is held in the variable -- rc_window The window size and location can be changed at any time by using the procedure -rc_new_window-, which destroys the current rc_window (if it is a live window) and creates a new one: -- rc_new_window(width, height, xloc, yloc, setframe) This creates a new window with the given width and height and location of top left corner (in screen coordinates), after destroying the old window if necessary, and assigns their values to rc_window_xsize rc_window_ysize rc_window_x rc_window_y It assigns the new window widget record to the variable -rc_window-. If the boolean -setframe- is true, then it also sets the clipping boundary to be at the window frame, puts the user coordinate frame in the standard location (origin at middle of window, y axis going up) and locates the turtle at the centre facing right. This sets all the following variables (described in more detail below): Clip boundary: rc_xmin, rc_ymin, rc_xmax, rc_ymax Coordinate frame: rc_xorigin, rc_yorigin, rc_xscale, rc_yscale Turtle state: rc_xposition, rc_yposition, rc_heading If -setframe- is false rc_new_window leaves those variables untouched. See the section on rc_mouse_setup, below. -- rc_setsize() This checks the current size of the window (which may have been altered interactively by the user, and re-sets the variables rc_window_xsize rc_window_ysize It is called by rc_clear_window and rc_start, in case the window size has changed. rc_setsize, or one of the procedures that use it, should be called when the window size has changed, e.g. using the mouse. -- rc_clear_window() Clears the window, and calls rc_setsize, in case the size has changed. -- Setting or altering the coordinate frame relative to window -------- Users can redefine the coordinate transformation procedures rc_transxyin and rc_transxyout, described below. The default versions are adequate for simple tasks, and make use of the four variables defining the user coordinate frame relative to the window coordinates. -- rc_xorigin, rc_yorigin, rc_xscale, rc_yscale The numbers may be integers, decimals, ratios, etc. and may be positive or negative. The system starts with default values that put the origin in the middle of the window, with rc_yscale set to -1, so that the y-axis goes up the screen not down. -- rc_set_coordinates(xorigin, yorigin, xscale, yscale) This procedure simplifies altering the user's coordinate frame. -- rc_shift_frame_by(x, y) Moves the origin of the frame by x along and y up, in user coordinates. -- rc_stretch_frame_by(scale) Alters the scales, rc_xscale rc_yscale by the factor scale. For rotations of the user frame see section on RC_ROTATE_XY below. -- Drawing and jumping relative to current location and heading ------- In addition to procedures that take absolute user coordinates there are some that perform actions relative to the current drawing state represented by a position and a heading, as in the LOGO "turtle". The "current" location and heading relative to which some of the drawing and jumping commands are interpreted, is represented by the global variables: -- rc_xposition, rc_yposition, rc_heading where the first two are coordinates in the user frame, and the latter is a heading in degrees, measured counter-clockwise from the 3 o'clock position (heading horizontal to the right), if rc_xscale is positive. The following commands are provided -- rc_turn(angle) Alter rc_heading by angle degrees (counter-clockwise), and normalise rc_heading to lie between 0 and 360 -- rc_jump(amount) Amount is a number. Alter location by moving -amount-, in user coordinates, in direction of current heading (rc_heading). Uses rc_newposition to calculate new location. -- rc_jumpby(dx, dy) dx, dy are numbers. Add them to x and y coordinates of turtle. Does not alter heading. -- rc_drawto(pointcoords) Takes a point represented by either two numbers or a point data structure on which -rc_destpoint- works. Changes turtle's location but not its heading. If rc_clipping is true, will not draw outside the clipping boundary, though will allow turtle to end outside it. -- rc_drawby(dx, dy) dx, dy are numbers. Draw from current location to location got by adding dx and dy to x and y coordinates of turtle. -- rc_draw(amount) Like rc_jump, but draws. -- rc_point_here() Draws a point at the current location. -- rc_newposition(amount) -> newy -> newx This is the procedure that is used to work out the new location when moving forward from the current location by amount steps. -- rc_draw_rectangle(width, height) This draws a rectangle of given dimensions (in user coordinates) with top left corner at current location, and lines horizontal and vertical. -- rc_draw_oblong(width, height, radius) This procedure uses * XpwDrawRoundedRectangle to draw a rectangle with rounded corners, with the given width and height (in user coordinates) with top left corner at current location, and lines horizontal and vertical. The third argument is used in combination with rc_xscale and rc_yscale to compute the two "radius" arguments required for XpwDrawRoundedRectangle. -- rc_arc_around(radius, degrees) Both arguments are numbers. The radius must be positive, representing a length in user coordinates. Draw an arc, starting in current heading, with radius given, curving to left if angle is positive otherwise to right. -degrees- is the angle of the arc, in degrees. The new heading of the turtle will be old heading plus degrees. New location will be at the end of the arc. (Combinations of 90 and 45 degrees seem to reveal bugs in the XDrawArc facility in X11R4, as of May 1990. ???) -- Absolute drawing and jumping --------------------------------------- The following commands are provided -- rc_jumpto(pointcoords) Takes two numbers or a point data structure. Changes the location of the turtle. Does not alter rc_heading. Permits jumping outside the clipping boundary or even outside the window, or off the screen. -- rc_drawpoint(pointcoords) Takes two numbers or a point data structure. Draws a point at the location specified. Does not alter the turtle's location or heading. -- rc_drawline(pointcoords1, pointcoords2) Takes two points, each of which can be represented either by two numbers or by a point data structure. It draws from the first point to the second. Does not alter the turtle's location or heading. If rc_clipping is true, this will not draw outside the clipping boundary. See section on "Clipping facilities", below. -- rc_draw_arc(pointcoords, width, height, angle1, angleinc) Draws an arc on a circle or ellipse bounded by the rectangle whose top left corner is pointcoords (a point data structure or two numbers), with given width and height, all in user coordinates The arc is defined by the start angle of the radius angle1 and the amount it is to be increased angleinc, measured from the three O'clock position, in 64ths of a degree, counterclockwise (negative angles are measured clockwise). (The underlying XDrawArc seems to produce buggy arcs in some circumstances.) Does not alter the turtle's location or heading. To draw a complete circle make width and height the same and angleinc 360*64. -- Saving and restoring "turtle" state -------------------------------- -- rc_save_state() -> state Saves position location and heading in a three element vector -- rc_restore_state(state) Takes a three element vector and restores the position and heading. -- Transformations from and to user coordinates ---------------------- Using a coordinate frame different from that used by the underlying graphics window, based on screen pixels is made easy, as follows. All input and output routines go via two user-definable procedures -- rc_transxyout(x_user, y_user) -> y_win -> x_win Used to transform use coordinates to window coordinates -- rc_transxyin(x_win, y_win) -> y_user -> x_user Used to transform window coordinates to user coordinates All output routines transform from user coordinates to window coordinates via the first and all input routines transform them via the second. The procedures have default definitions that make use of the following global numeric variables that define the user's coordinate frame relative to the window coordinates, in the obvious way: rc_xorigin, rc_yorigin, rc_xscale, rc_yscale For details of the default definitions of these procedures: SHOWLIB * RC_GRAPHIC If rotations relative to the window are required then do the following lib rc_rotate_xy rc_rotate_xy -> rc_transxyout; This will replace the default output transformation by one that can do transformations. See the section on transformations. The library also provides a procedure to assign to rc_transxyin, for handling input from the mouse properly. See LIB * RC_MOUSE below. There are also procedures for changing, saving and restoring, the current user coordinate framework, described above. -- Using LIB * RC_ROTATE_XY to rotate user coordinate frame The command lib rc_rotate_xy or uses rc_rotate_xy makes available an active variable to hold the current angle of rotation and two procedures. The rotation is assumed to be about the point chosen as the origin of the user's coordinate frame. Warning: all though all the drawing of lines and points using the rc_procedures will be rotated, printing will not be. -- rc_frame_angle (active variable, current rotation angle) This is the active variable (See HELP * ACTIVE_VARIABLES) holding the current frame angle. It is an active variable in order that whenever it is updated two additional hidden variables are set corresponding to the sin and the cosine of the angle, used by the rc_rotate_xy procedure so that it doesn't have to compute them each time it is called. -- rc_rotate_frame(angle) This is equivalent to the following, but slightly more efficient: rc_frame_angle + angle -> rc_frame_angle -- rc_rotate_xy(user_x, user_y) -> window_y -> window_x This procedure can be assigned to rc_transxyout and will ensure that in future the angle assigned to rc_frame_angle will be used in calculating window coordinates from user coordinates. -- Temporarily altering the user coordinate frame --------------------- It is sometimes convenient to have a procedure that uses an existing function but draws at a different scale or angle or relative to a different origin. If the global variables that define the user coordinate frame are made dlocals of the drawing procedure then the frame will automatically be reset when the procedure exits. E.g. define rc_do_relative(rc_xorigin,rc_yorigin,rc_xscale,rc_yscale,proc); lvars proc; ;;; the drawing procedure dlocal rc_xorigin, rc_yorigin, rc_xscale, rc_yscale; ;;; call the drawing procedure proc() enddefine; If rc_rotate_xy has been assigned to rc_transxyout, and different rotations of the frame are to be used, then the procedure do_relative can be defined to have an additional input variable, rc_frame_angle, which should also be declared dlocal in do_relative. -- Printing strings in the window ------------------------------------- -- rc_print_at (pointcoords, string) Print the string at location represented by two numbers or a point data structure. -- rc_print_here(string) Print the string at the current turtle location. -- Clipping facilities used by rc_drawline ---------------------------- Although the underlying windowing primitives may automatically clip lines when they go beyond the window boundary, users can also clip relative to an internal frame. -- rc_clipping (default true) If the variable rc_clipping is -true- then lines are clipped if they go beyond limits defined by the following variables: -- rc_xmin rc_xmax rc_ymin rc_ymax These are used by the procedure rc_drawline. I.e. only the portion of the line within the clipping rectangle is drawn, up to the clipping boundary. It may turn out that doing the clipping inside POPLOG is faster than leaving it to the lower level windowing facilities. Experiment with rc_clipping set both true and false. NOTE: The values of these variables are in window coordinates, not user coordinates. -- LIB * RC_CLIP_REGION allows clipping relative to user coordinates -- (David Young, November 1992) LIB *RC_CLIP_REGION provides an extension to the *RC_GRAPHIC utilities which simplifies setting the clipping region in some applications. -- rc_clip_region(REGION) -- rc_clip_region(XMIN, XMAX, YMIN, YMAX) In the first form, REGION should be a list of length 4 containing values for XMIN, XMAX, YMIN and YMAX. In the second form, these values are given as separate arguments. The clipping region (see *RC_GRAPHIC/Clipping) is set to the rectangular region specified by the four values in user coordinates. (Note that rc_xmax etc. are in window coordinates - all that -rc_clip_region- does is to translate its arguments using -rc_transxyout- and to set rc_xmax etc.) -rc_clipping- is not affected. -- Optional use of two numbers or point data-structure (pointcoords) -- Most of the rc_ routines that take two coordinates to represent a point can also take a point data-structure provided that the user- definable procedure -rc_destpoint- if applied to such a data-structure returns two numbers, an x coordinate and a y coordinate. Similarly, the user-definable procedure -rc_conspoint- is used by rc_thispoint to create a point data-structure. The specifications above use the argument type "pointcoords" to represent the option of either two numbers or a point data structure. For example if pt1 is a point data-structure and rc_destpoint(pt1) returns the values x1 and y1, and similarly for pt2, x2, y2, then the following commands are equivalent: rc_drawline(x1, y1, x2, y2); rc_drawline(pt1, pt2); rc_drawline(x1, y1, pt2); rc_drawline(pt1, x2, y2); The default value of -rc_conspoint- is -conspair- and the default value of -rc_destpoint- is -destpair- so that Pop-11 pairs, created using -conspair- can be used for points. -- rc_conspoint(x,y) -> point User-definable procedure for creating a point data-structure from two coordinates. Default value is conspair -- rc_destpoint(point) -> y -> x User-definable procedure for producing two coordinates given a point data-structure. Default value is destpair -- rc_getxy(pointcoords) -> y -> x Given either a point data-structure or two numbers representing a point it returns the two numbers. This is used by all the procedures that accept either two numbers or a point structure to ensure that two numbers are available inside the procedure. -- The current window (rc_window) ----------------------------------- All the rc_graphic procedures make use of a current window, held in the variable -rc_window- Its size and location on the screen can be controlled by the user. The current window is set up using the procedure -rc_new_window- described above. -- Drawing in multiple windows ---------------------------------------- Each time rc_new_window is invoked it checks if rc_window is a live window, in which case it destroys it, and then after creating a new widget it assigns it to rc_window. If you wish to preserve the existing window and create a new one do the following: ;;; Save existing window vars oldwindow = rc_window; ;;; Prevent it being destroyed by rc_new_window false -> rc_window; ;;; Create new window rc_new_window(400, 400, 300, 500, true); ;;; save the new window vars newinwdow = rc_window; Then in order to draw in either window just assign it to rc_window and call the drawing functions. They all use rc_window non-locally. -- Coordinate transformations: rc_transxyin, rc_transxyout ------------ The package also includes facilities for transforming from user coordinates to window coordinates via a procedure that is user definable rc_transxyout. The default value of this procedure makes it easy to change the origin and scale, or to reflect the x or y axis about the origin, using the global variables -- rc_xscale, rc_yscale, -- rc_xorigin, rc_yorigin; Clipping utilities are also provided. The values of the scale and coordinate origin variables are used by the default window-to-screen transformation procedure -rc_transxyout- and screen-to-window transformation procedure -rc_transxyin-. By default the origin is set to the middle of the window, so that rc_jumpto(0,0) will make the current location the centre of the screen. By default rc_xscale is set to 1, so that x increases to the right and rc_yscale is set to -1 so that y increases upwards. -- LIB * RC_SET_SCALE: setting scales in inches, cm, frame units ------ This library has to be loaded explicitly, using the "uses" or "lib" command: lib rc_set_scale or: uses rc_set_scale The procedure rc_set_scale- makes it easy to set the scale variables so that the user coordinate units are understood in terms of inches, centimetres or multiples of the window width and height. -- rc_set_scale(type, xscale, yscale) The type is a word or false, indicating how the second and third argument, both numbers, are to be interpreted, as follows. If type is "inches" -Then xscale is the number of inches per user unit to right -Then yscale is the number of inches per user unit up screen "cm" -Then xscale is the number of centimetres per user unit to right -Then yscale is the number of centimetres per user unit up screen "frame" -Then xscale is the number of window widths per user unit to right -Then yscale is the number of window heights per user unit up screen false Just use xscale and yscale as given (y positive upwards) For example, the command rc_set_scale("inches", 2, 2) Implies that the command rc_draw(1) should draw a line of 2 inches. rc_set_scale("frame", 0.25, 0.25) Implies that the command rc_draw(1) should draw a line that is a quarter of the width of the rc_window, assuming that the width and height are the same. For the first two options to work a global variable has to be set by the user: -- rc_pixels_per_inch (default 90) This represents the number of dots (pixels) per inch on the screen. It may be possible to have this computed automatically, but it will not need to change for a particular terminal once set. -- LIB * RC_SET_COORD_FRAME can simplify setting scales and origins --- (David Young, November 1992) LIB *RC_SET_COORD_FRAME provides an extension to the *RC_GRAPHIC utilities which simplifies setting scales and origin for many applications. -- rc_set_coord_frame(TYPE, WINDOW_REGION, USER_REGION) The procedure sets the parameters -rc_xscale-, -rc_yscale-, -rc_xorigin- and -rc_yorigin-. TYPE can be as in LIB RC_SET_SCALE (see *RC_GRAPHIC/rc_set_scale) - i.e. it can be , "inches", "cm", or "frames", and it specifies the units used for WINDOW_REGION. In addition, TYPE can be "existing" - see below. WINDOW_REGION is normally a list of length 4 (but see below), specifying a rectangular region of -rc_window-, in the order [minX maxX minY maxY], in window coordinates. (Window coordinates have X running from left to right and Y from top to bottom, with the origin in the top left corner of the window.) USER_REGION is normally a list of length 4 specifying a rectangular region of user coordinates in the same way. The scale and origin are set so that USER_REGION is mapped onto WINDOW_REGION. If TYPE is "existing", then WINDOW_REGION specifies a region relative to the existing user coordinates, and not in window coordinates at all. In this case the procedure implements an incremental change from one user coordinate frame to another, rather than referring back to the absolute window coordinates. Instead of specifying the regions as lists, either or both may be specified as 4 separate numerical arguments. If either region is actually an array, its boundslist is used. -- Examples 1. To put the origin of user coordinates in the middle of the window, with X running left to right and Y running bottom to top (as is conventional for drawing graphs, for instance), and with 20 user units from left to right and from top to bottom, do: rc_set_coord_frame("frame", [0 1 1 0], [-10 10 -10 10]); Note how the last two entries in WINDOW_REGION have been reverse to force the reversal in Y-axis direction. The call could have been: rc_set_coord_frame("frame", 0, 1, 1, 0, -10, 10, -10, 10); 2. Suppose ARR is a 2-D array, and you want to make entries in this array correspond to a region of the window 100 screen pixels wide by 50 screen pixels high, set in by 10 pixels from the top left corner of the window. Then do: rc_set_coord_frame(false, [10 109 10 59], ARR); -- LIB * RC_DRAWGRAPH : graph drawing package ------------------------- This library has to be loaded explicitly, using the "uses" or "lib" command: lib rc_drawgraph or: uses rc_drawgraph rc_drawgraph(xmin,xmax,ymin,ymax,xstep,ystep,xline,yline,xincr,fun) -> minyvalue -> maxyvalue This provides a procedure for drawing a graph of a function of one variable. It draws the x and y axes and marks them at intervals specified by the user. It then draws the function by computing its y value for values of x within a range specified by the user at specified intervals, and then interpolates. It returns the highest and lowest values found for the function, in case these are useful for re-scaling the picture. The procedure rc_drawgraph takes the following arguments xmin,xmax,ymin,ymax, ;;; limits of graph xstep,ystep, ;;; steps between marks on axes xline, yline, ;;; lengths of marks on axes incr, ;;; amount by which to increment x procedure fun ;;; function for graph And produces two results -> minyvalue -> maxyvalue These two outputs are useful if you want to know whether the graph has all remained visible, etc. If the user wishes to further annotate the graph, the procedure rc_print_at can be used to print labels, etc. A more sophisticated extension that provides for annotated axes, parametrised functions, etc. is described in TEACH * RC_GRAPHPLOT, HELP * RC_GRAPHPLOT -- USEFUL ADDITIONAL X FACILITIES ------------------------------------- The following sections describe facilities that are not provided directly in LIB RC_GRAPHIC but are made available by the underlying X interface. The are all explained more fully in HELP * Xpw and files cross-referenced there. E.g. to change the colour used for drawing in the current window on a colour display, do something like: XpwSetColor(rc_window, 'red'); XpwSetColor(rc_window, 'green'); XpwSetColor(rc_window, 'black'); -- Changing line drawing style ---------------------------------------- rc_linewidth -> integer; [active variable] integer -> rc_linewidth; Access or update line width of the current window. The integer can be 0 upwards. The following functions make use of macros defined in LIB XpwPixmap.ph that hold integer values. rc_linefunction -> integer; [active variable] integer -> rc_linefunction; Access or update line drawing function of the current window. The integer can be one of the draw functions listed in REF * XpwPixmap. The following draw functions are provided: GXclear GXand GXandReverse GXcopy (default) GXandInverted GXnoop GXxor GXor GXnor GXequiv GXinvert GXorReverse GXcopyInverted GXorInverted GXnand GXset rc_linestyle -> integer; [active variable] integer -> rc_linestyle; Access or update the line style of the current window, where the integer is one of: LineSolid (default) LineOnOffDash LineDoubleDash -- Changing foreground/background colours ----------------------------- Facilities described in REF * XpwPixmap include mechanisms that access or update the foreground or background colour of the widget. -- Changing font ------------------------------------------------------ XpwSetFont(rc_window,) -> Changes the current font used by rc_print_at. Returns a number if it succeeds, and false if it fails. The is a string. E.g. XpwSetFont(rc_window,'9x15bold') See REF * XpwCore -- LIB * RC_MOUSE - mouse interaction in the graphics window ---------- The command lib rc_mouse or uses rc_mouse makes available an extension providing mouse-based interaction facilities, as follows. -- rc_mouse_draw(listpoints, stop_button) This is used to draw pictures made of straight lines in the current graphic window (rc_window), using the mouse buttons to indicate the ends of the lines. It starts drawing as soon as a button, other than the stop_button, is pressed in the graphics window, then uses a "rubber-band" facility to follow the mouse motion. Whenever a button is pressed it then draws a line which is preserved thereafter. If it is the stop_button, then the drawing stops and the procedure exits. The first argument, listpoints, should be true if the procedure is to produce a list of points (produced by applying rc_conspoint to the x and y user coordinates), and false if it should not produce a list of points. In the latter case it returns no result. The second argument is the number of the button that is to indicate when the final point has been drawn. so rc_mouse_draw(true, 3) -> pointlist; will get a picture made of lines, returning a list of point data-structures, the picture being terminated by pressing mouse button 3. The number of buttons provided on different mice will be different, so find out what works on your machine. On HP machines left button is no 1, right button number 3 and both buttons together count as button 2. The use of rc_mouse_draw, which packages the use of the mouse into the most convenient form, is illustrated in TEACH * RC_GRAPHIC It is implemented in terms of the more general and basic facilities described below. Calling -rc_mouse_draw- will cause -rc_mouse_setup- to be run on -rc_window- if it has not done so already. -- rc_rubber_function (integer) This variable specifies the line-drawing function to be used for the "rubber banding", i.e. drawing a temporary line between the last line end and the current mouse position. Its default value is GXxor. On colour terminals and on some black and white terminals it may be necessary to do GXequiv -> rc_rubber_function; to get the required effect. -- rc_transxyin(x_window, y_window ) -> y_user -> x_user ; This procedure is defined to translate from window to user coordinates when the mouse button is pressed. If rc_rotate_xy is assigned to rc_transxyout, then rc_rotate_xyin should be assigned to rc_transxyin -- rc_mouse_setup(widget) This makes the facilities described below applicable to the graphics widget to which it is applied. If the value of the variable rc_mouse_setup is a procedure then the command rc_mouse_setup(rc_window) is given automatically by the procedures rc_new_window and rc_start described above. This turns on the lists rc_button_procedures and rc_move_procedures, for that window, as described below. If rc_mouse_setup has not been invoked, then the list has no effect. -- rc_mouse_disable(widget) This turns off mouse button and movement processing for the widget -- rc_mousing (boolean, default false) Making this true enables automatic handling of mouse events by the procedures in (or named in) the list rc_button_procedures and rc_move_procedures. Making it false disables handling. -- rc_button_procedures (list, default []) -- rc_move_procedures (list, default []) These are lists of procedures or procedure names. If rc_mouse_setup has been applied to a widget (e.g. rc_window) AND rc_mousing is non-false, then the procedures in (or named in) the list are run when a mouse move event or a button event occurs in the widget specified, i.e. when a mouse button is pressed or released. If rc_mousing is false, or rc_button_procedures is an empty list, then nothing happens when a button is pressed or released. Similarly if rc_move_procedures is an empty list, movement of the mouse produces no effect. If the list rc_button_procedures is non-empty and rc_mousing is non false, then, whenever a mouse button event happens, each of the procedures is run with three arguments, 1. the widget (usually rc_window) 2. a Pop-11 data item, i.e. "button" 3. a number representing which button was involved (e.g. 1, 2, or 3), a positive integer if the button was pressed, and negative if it was released. If a mouse-button "event handling" procedure is to make use of the position of the mouse cursor when the button was pressed it can do the following, to get the position in window coordinates and then transform them to screen coordinates. rc_transxyin(XptVal rc_window(XtN mouseX, XtN mouseY)) -> (x, y); If the list rc_move_procedures is non-empty and rc_mousing is non false, then, whenever a mouse motion event happens, each of the procedures is run with three arguments, 1. the widget (usually rc_window) 2. a Pop-11 data item, i.e. "move" 3. an integer, which is 0 if no button is down at the time of the move, 256 if button 1 is down, 512 if button 2 is down and 1024 if button 3 is down. For combinations of buttons the numbers are ORed together. (I.e. bits 8,9 and 10 are used to indicate which buttons are down.) If a mouse-motion "event handling" procedure is to make use of the position of the mouse cursor when it is moved it can use the same techniques as for mouse_button events. All these facilities are packaged up for easy use in the next procedure -- rc_mouse_do(first_input, other_input, test_exit) This procedure is invoked with three procedures as inputs, each taking three arguments. It makes it easy to get the mouse to draw a picture made of straight lines, and to record the locations of the ends of the lines. The three procedures are each applied to four things 1. The x coordinate, in the user frame 2. The y coordinate, in the user frame 3. If it is a button event then the number of the button pressed (releases are ignored) and if it is a move event the number indicating whether any button is down and if so which, as indicated above. 4. The word "move" or "button" to indicate the type of event The first procedure (first_input) is applied only on the first occasion the button is pressed. The second procedure (other_input) is applied on all other occasions. The third procedure (test_exit) is applied on EVERY occasion, and if it returns a non-false result the procedure rc_mouse_do terminates. Locally rc_mouse_do makes rc_mousing true, restricts the list rc_button_procedures to contain only a special privately defined procedure that brings the above about. Calling -rc_mouse_do- will cause -rc_mouse_setup- to be run on -rc_window- if it has not done so already. It uses repeated calls of syssleep to ensure that the procedure waits until the picture has been drawn. If the test_exit procedure returns a non-false result this interrupts the sleeping. The procedure rc_mouse_draw, described above, is defined by applying rc_mouse_do to three simple procedures. For details SHOWLIB * RC_MOUSE The callback facilities used here are described in REF * XTOOLKIT -- Asynchronous mouse-button event handling --------------------------- If rc_mousing is made true and the names of one or more appropriate procedures are put in the list rc_button_procedures, then the procedures will be run whenever a mouse button is clicked in the graphics window (if rc_mouse_setup has been applied to it). However if the procedure rc_mouse_do, or a procedure defined in terms of it, e.g. rc_mouse_draw, is running, then it will supersede the global assignment to rc_button_procedures by re-setting it locally to contain only one procedure required for rc_mouse_do. -- LIB * RC_CONTEXT: USING SEVERAL WINDOWS AND SWITCHING BETWEEN THEM - The procedure -rc_context- and its updater are provided to make it easy to manipulate a number of different rc_graphic windows and to switch between them. As explained above, the rc_graphic procedures operate on the _current_ window held in the variable rc_window, and use a collection of global "context" variables defining the state of that window, its size, the current x and y origin, the transformation procedure to map user coordinates onto window coordinates, etc. Thus in order to be able to switch between different windows, it is necessary to be able to save the context variables associated with the current window before setting the variables required for the new window. This facility is provided by the procedure rc_context and its updater. In order to use it it is necessary to load LIB * RC_CONTEXT. However before doing that you need to consider which global variables you require to define the context to be saved and restored. -- rc_context_vars: specifying the context variables For example, you may wish to associate different transformation procedures mapping user to window coordinates with different windows. In that case rc_transxyout (explained above) would need to be saved and restored when switching between windows. However if the same mapping is used for all windows then it is wasteful to save and restore the mapping procedure, though you may still wish to save and restore rc_xorigin, rc_yorigin, rc_xscale and rc_yscale, for instance. A mechanism is provided to allow the user to specify the variables to be saved and restored. This is done by assigning a list of their names to rc_context_vars. If this is not done BEFORE loading LIB RC_CONTEXT, a default set of context variables will be used, as follows. -- The default rc_context_vars ;;; window variables rc_window ;;; this should ALWAYS be the first item rc_window_x rc_window_y rc_window_xsize rc_window_ysize ;;; clipping variables rc_clipping rc_xmin rc_ymin rc_xmax rc_ymax ;;; turtle state rc_xposition rc_yposition rc_heading ;;; transformation to user coordinates rc_transxyin rc_transxyout rc_xscale rc_yscale rc_xorigin rc_yorigin ;;; active variables rc_frame_angle rc_linewidth rc_linestyle rc_linefunction ;;; callback facilities rc_button_procedures rc_move_procedures rc_mousing ;;; a field for the user to associate with each window rc_props If the only thing you are interested in saving and restoring is the current location and heading of the "turtle" then you should do [ rc_window ;;; this should always be the first item ;;; turtle state rc_xposition rc_yposition rc_heading ] -> rc_context_vars; It is then up to you to make sure that you never use any procedures that depend on the other variables that may have different values for different windows, such as rc_window_x and rc_window_y. You may wish to use a different rc_rubber_function in different windows, for use with rc_mouse_draw, in which case it can be added to the list. NB The list should always include rc_window as the FIRST item, since that is the variable that holds a pointer to the window itself, and that is used by rc_destroy_context NB The list rc_context_vars MUST be set up BEFORE lib rc_context is compiled, since the references are compiled into the procedures. If the variables to be saved and restored are changed after the library has been compiled then create the new version of rc_context_vars and then recompile. However, previously created contexts will be unusable. -- rc_context() -> context -- context -> rc_context() Loading LIB RC_CONTEXT provides this procedure and its updater. In order to create a record of the current context, call the procedure rc_context with either false or a previously existing context vector as argument. It will return a context vector containing all the saved values for the current context, where the context is defined by the list rc_context_vars, as explained above. The context vector returned by rc_context can later be used with its updater to restore the context. If rc_context is invoked with a context vector as argument, it will store the values in that vector and return it. If called with -false- as argument it creates a new context vector and returns that. After having saved the context corresponding to the current window you may wish to create a new window with its own set of values. You can do this either using -rc_new_window- or else by assigning -false- to rc_window and calling -rc_start-, as illustrated below. -- rc_destroy_context(context) This procedure can be used to dispose of a context. It will destroy the window and remove the pointer to it from the context, so that the record can be garbage collected. -- Example of use of more than one window A typical way to use the facility provided by LIB RC_CONTEXT would be as follows ;;; Load the library lib rc_context rc_start(); ;;; create or clear a window ;;; .... do some drawing ... ;;; Save the current context in a variable called window1; vars window1 = rc_context(false); ;;; Then ensure that rc_start creates a new window false -> rc_window; rc_start(); ;;; alternatively use rc_new_window ;;; draw some pictures, etc. ;;; Now save the new window and its context as window2 vars window2 = rc_context(false); ;;; Restore the old window window1 -> rc_context(); ;;; draw more pictures ;;; Now save window1, using the previous record, and restore the second ;;; window rc_context(window1) -> window1; window2 -> rc_context(); etc. -- ADDITIONAL OPERATIONS ON GRAPHICS WINDOW --------------------------- The REF * XpwGraphic file describes additional mechanisms that can be applied to the rc_window widget in order to change or interrogate the state of the window, including functions for copying or inserting sub-images. -- INTERFACING TO A DIFFERENT WINDOW MANAGER -------------------------- If the RC_GRAPHIC package is to be ported to a different window system, a small number of interface procedures will need to be redefined. In particular, all those whose names start "xt_" "Xpt" or "Xpw" will need to be re-defined if the package is ever re-implemented in terms of some other graphics system than LIB * XptNewWindow or LIB * XpwGraphic . In the following list of low level interface procedures, used by LIB RC_GRAPHIC, coordinates are screen-based or window-based, unlike the "turtle" procedures, which employ user coordinates. For full details on the low level interface procedures see the rc_ library files. XpwDrawPoint(window,x,y); Takes a window (i.e. rc_window) and two coordinates (integers). It draws a point. XpwDrawLine(window,x1,x2,y1,y2) Takes a window and four coordinates (integers), and draws a line. XpwDrawRectangle(window, x, y, width, height). Draws a rectangle top left corner x,y, with horizontal and vertical sides of the lengths given. XpwDrawArc(window,x,y,width,height,start_angle,angle_incr) Draws an arc on a circle or ellipse bounded by the rectangle whose top left corner is (x, y), with given width and height. The arc is defined by the start_angle (relative to the centre) and the amount the angle is to be increased, angle_incr. See HELP * XpwGraphic XpwDrawString(window, x, y, string) This takes a window, two coordinates and a string, and prints the string in the window at the location specified. XpwClearWindow(window); This takes a window and clears it XptDestroyWindow(window); This takes a window and destroys it XptNewWindow(namestring, size-position-vector, arglist, class) -> w This takes several arguments and returns a graphics window widget record. The second argument defines size and position of window on screen. Used in xt_new_window. For details SHOWLIB * xt_windows XpwGraphic This is not a procedure but the name of a window class, used by xt_window. It will probably not be required in any re-implementation based on some other window system. XptVal (,...,) -> (,...,) ,..., -> XptVal (,...,) This is used for accessing and altering various features and capabilities of the widget. (REF * XptVal) The next three are defined in LIB RC_GRAPHIC xt_islivewindow(window) -> boolean This will have to be re-defined for a different windowing system. xt_new_window(string,xsize,ysize,xloc,yloc) -> window This will have to be re-defined for a different windowing system. The string is the name of the window. If user programs employ any other Xpw or Xpt facilities, then they too would have to be ported to the new interface. -- See Also ----------------------------------------------------------- HELP * X This gives a more comprehensive overview of documentation on the POPLOG X interface. TEACH * RC_GRAPHIC TEACH * RC_GRAPHPLOT These two give tutorial introductions to the relative coordinates graphics facilities. HELP * RC_GRAPHPLOT Describes an extension to this file SHOWLIB * RC_GRAPHIC, * RC_ROTATE_XY, * RC_MOUSE, * RC_DRAWGRAPH SHOWLIB * RC_CONTEXT, * RC_GRAPHPLOT, * RC_GRAPHPLOT2 TEACH * XTOOLKIT Introduction to the POPLOG X Toolkit interface TEACH * Xpw Tutorial examples of the use of the POPLOG Widget Set HELP * Xpw An overview of the POPLOG Widget Set -- Acknowledgements --------------------------------------------------- To Roger Evans, Ian Rogers and Jon Meyer for designing and implementing the basic facilities underlying this package. Jon Meyer designed and implemented the POPLOG Widget Set described in HELP * Xpw. Andreas Schoter and Adrian Howard helped to convert LIB RC_GRAPHIC and associated libraries, to work for POPLOG V14. Thanks to Ian Rogers for helping me understand how to use the relevant X facilities, and to David Hogg and David Young for discussions and suggestions regarding requirements. David Young designed and implemented the rc_graphplot extensions. --- C.x/x/pop/help/rc_graphic --- Copyright University of Sussex 1990. All rights reserved. ----------