TEACH RC_GRAPHIC Aaron Sloman Feb 1991 This file provides an easy introduction to the Pop-11 high level interface to X. A more general overview is provided in HELP * X. In order to use this teach file you must have the Poplog X interface libraries in your path (see HELP *X) and be using an X server (workstation or XTerm) running at least X Version 11, preferably release 4 or later. You should already know how to move windows around on the screen using the mouse. THE "RELATIVE COORDINATES" (RC) GRAPHIC PACKAGE IN X CONTENTS - (Use g to access required sections) -- Introduction -- Getting started -- Starting and re-starting the window and drawing pictures -- Defining a picture drawing procedure -- Changing line widths and line styles -- A picture made of pictures -- Letting the program do "clipping" -- Printing text and changing fonts -- Drawing curved lines (circular arcs) -- Changing the coordinate frame: origin and scale -- Setting the scale in inches, cm or frame-units -- Creating a new window, with given size and location on screen -- Rotating the user coordinate frame -- Using the mouse to draw a picture "by hand" -- Changing the colour used to draw with -- Saving a picture drawn with the mouse, and re-drawing it -- Example of use of rc_drawgraph -- A more sophisticated graph drawing package -- Using more than one window -- Further reading -- Introduction ------------------------------------------------------- This file consists entirely of illustrative examples showing how you can get started using the "relative coordinates" graphical facilities in X. They are more fully described in the HELP * RC_GRAPHIC file. The LIB * RC_GRAPHIC package makes it easy for the programmer to create a graphics window and define a coordinate frame with origin anywhere in the window and to think in terms of this coordinate frame instead of having to think in terms of pixel-based window coordinates with the origin in the top left hand corner. All the transformations from user coordinates to window coordinates are handled automatically. Some of the procedures described below use the idea (borrowed from the LOGO programming language) of a mythical "turtle" that has a position and a "heading" on the graphics window. It can either be made to jump or draw from its current position in the direction of its current heading, or it can be given coordinates of the ends of lines to draw. More general graphics facilities are also described. -- Getting started ---------------------------------------------------- To start using the package, ensure that you are using Poplog with the X Window System version 11 release 4, or later. (Consult your local Poplog administrator if necessary.) After starting Poplog the easiest procedure is to get this teach file into VED, and then to mark and load commands that illustrate the facilities. First it is necessary to ensure that you can access the Poplog X interface libraries. If you are going to use X regularly you can put into your init.p file uses popxlib If you have not already done that, you can mark and load that line now. Next you must get the rc_graphics package loaded. This is made of a number of fragments. The main part is compiled thus: lib rc_graphic It will automatically compile a number of libraries that provide X facilities in Poplog that are used by the programs described below. After compiling lib rc_graphic you can run the following examples, by marking and loading them in VED. (See TEACH * MARK, TEACH * LMR) -- Starting and re-starting the window and drawing pictures ----------- The following gives some simple examples of the use of the package. It should be possible to mark and load the commands: ;;; Start (or re-start) the window and set up coordinate frame. rc_start(); ;;; If the window is not in a convenient place you can move it using ;;; the mouse; ;;; Draw a line, from the "turtle"'s current location in current heading rc_draw(30); ;;; Draw the X axis, from point (-200, 0) to point (200, 0) rc_drawline(-200, 0, 200, 0); ;;; Draw the Y axis rc_drawline(0, -200, 0, 200); ;;; Jump to the centre rc_jumpto(0, 0); ;;; Examples below all use degrees not radians, so false -> popradians; ;;; Make the turtle's heading 45 degrees (up and to the right) 45 -> rc_heading; ;;; That does not draw anything, but determines the effect of the next ;;; draw command. ;;; Draw a line in that direction, turn, and draw another line rc_draw(50); rc_turn(90); rc_draw(100); You can draw rectangles thus: rc_start(); rc_draw_rectangle(100, 50); rc_draw_rectangle(50, 100); and oblongs (rectangles with rounded corners) rc_start(); rc_draw_oblong(50,80,20); rc_draw_oblong(200,50,10); See HELP * RC_GRAPHIC/rc_draw_oblong ;;; Clear the picture rc_start(); -- Defining a picture drawing procedure ------------------------------- ;;; Define a procedure for drawing regular polygons. Mark and load this define polygon(side,num); lvars side, num, angle; ;;; A polygon with num sides requires turn angles of 360/num 360.0 / num -> angle; repeat num times rc_draw(side); rc_turn(angle) endrepeat; enddefine; ;;; Use the procedure to draw a square and a hexagon polygon(50, 4); polygon(50, 5); polygon(50, 6); ;;; clear the window rc_start(); -- Changing line widths and line styles ------------------------------- ;;; Try the polygon procedure again with different linewidths 5 -> rc_linewidth; polygon(90, 4); 10 -> rc_linewidth; polygon(90, 5); 15 -> rc_linewidth; polygon(90, 6); 2 -> rc_linewidth; ;;; Now try with different line "styles" (See HELP * RC_GRAPHIC) rc_jumpto(-100, -100); LineOnOffDash -> rc_linestyle; polygon(90, 4); ;;; re-set the default LineSolid -> rc_linestyle; polygon(90, 5); ;;; clear the window and re-set linewidth to the default rc_start(); 0 -> rc_linewidth; More sophisticated variations of line drawing style are described in HELP * RC_GRAPHIC/rc_linefunction -- A picture made of pictures ----------------------------------------- ;;; A procedure to draw a pretty pattern made of squares ;;; Mark and load this define cartwheel(side, sides, num); ;;; A program to make a pretty picture lvars side, sides, num, angle; 360.0 / num -> angle; repeat num times ;;; draw a polygon polygon(side, sides); ;;; rotate through angle degrees rc_turn(angle); endrepeat; enddefine; cartwheel(100, 8, 60); -- Letting the program do "clipping" ---------------------------------- ;;; Let the window boundary clip the picture, not this program false -> rc_clipping; rc_start(); cartwheel(100, 20, 60); ;;; Now set an internal clipping boundary and compare result and speed true -> rc_clipping; 450 ->> rc_xmax, ->rc_ymax; 50 ->>rc_xmin -> rc_ymin; rc_start(); cartwheel(100, 20, 60); false -> rc_clipping; -- Printing text and changing fonts ----------------------------------- ;;; Print some text in the window rc_print_at(-150, 165, 'What a PRETTY picture'); ;;; Change the font and try again (returns false if font not found) ;;; Repeat the SetFont call if necessary with a different font name XpwSetFont(rc_window,'9x15bold') => ;;; (may be necessary to do this twice) rc_print_at(-150, 145, 'What a PRETTY picture'); XpwSetFont(rc_window,'r24') => rc_print_at(-150, 120, 'What a PRETTY picture'); XpwSetFont(rc_window,'lucidasans-bold-24') => rc_print_at(-150, -100, 'What a PRETTY picture'); XpwSetFont(rc_window,'6x13bold') => rc_print_at(-150, -130, 'What a PRETTY picture'); -- Drawing curved lines (circular arcs) ------------------------------- ;;; Start with an empty picture, then draw a line rc_start(); rc_turn(45); rc_draw(30); ;;; draw a semi-circle with radius 50, curving left, through 60 degrees rc_arc_around(50, 66); ;;; draw a semi-circle with radius 50, curving to right 180 degrees rc_arc_around(50, -180); ;;; Note how the "turtle" acquires a new location and heading after ;;; each call of rc_arc_around rc_arc_around(20, -180); rc_arc_around(20, 180); rc_draw(30); rc_arc_around(10, 180); rc_draw(30); ;;; Make an interesting picture using arcs: rc_start(); rc_jumpto(-100, -100); repeat 60 times rc_draw(150); rc_arc_around(60,85) endrepeat; rc_start(); WARNING: on some X servers it appears that the arc drawing programs have a bug that causes the wrong arc to be displayed if the initial angle is a multiple of 45 degrees and the arc angle is 90 or -90 degrees. -- Changing the coordinate frame: origin and scale -------------------- To show the difference made by coordinate changes, do the following cartwheel(20, 15, 30); ;;; using procedure defined above ;;; Shift origin down and to the left by 50 units (user coordinates) ;;; comparing origin before and after rc_xorigin, rc_yorigin => rc_shift_frame_by(-50, -50); rc_xorigin, rc_yorigin => ;;; re-draw cartwheel with the same parameters - it's no longer central cartwheel(20, 15, 30); ;;; Check scale factors rc_xscale, rc_yscale => ;;; Reduce the scale to half the previous size rc_stretch_frame_by(0.50); rc_xscale, rc_yscale => ;;; re-draw cartwheel using same parameters as before cartwheel(20, 15, 30); ;;; Restore the previous scale rc_stretch_frame_by(2); rc_xscale, rc_yscale => rc_jumpby(-40, -40); ;;; re-draw cartwheel cartwheel(20, 15, 30); -- Setting the scale in inches, cm or frame-units --------------------- This is made possible by an extension to lib rc_graphics which has to be explicitly loaded, thus lib rc_set_scale or: uses rc_set_scale ;;; Assign the number of dots per inch on your screen (often 90): 90 -> rc_pixels_per_inch; ;;; change the number if necessary ;;; Clear screen etc. rc_start(); ;;; Make the draw and jump commands use 2 inch units. rc_set_scale("inches", 2, 2); rc_draw(1); rc_turn(135); rc_draw(1.5); ;;; Now try centimetre units rc_start(); rc_set_scale("cm", 1, 1); rc_draw(1); rc_turn(135); rc_draw(1.5); ;;; Now set the scale in terms of frame size. rc_start(); ;;; Make the draw and jump commands use 1/4 frame units rc_set_scale("frame", 0.25, 0.25); rc_draw(1); rc_turn(135); rc_draw(1.5); ;;; Re-set default unit to be pixel based rc_start(); rc_set_scale(false, 1, 1); rc_draw(100); rc_turn(135); rc_draw(150); For more information see HELP * RC_GRAPHIC/rc_set_scale -- Creating a new window, with given size and location on screen ------ ;;; Replace the window with one of width 500, height 600, top left ;;; corner at location 520 along 200 down, and re-set the origin to the ;;; middle of the new window rc_new_window(500, 600, 520, 200, true); ;;; The value true means: set new default origin and scale ;;; draw in the new window cartwheel(100, 20, 60); -- Rotating the user coordinate frame -------------------------------- ;;; Load library for rotating coordinate frame lib rc_rotate_xy rc_start(); rc_jumpto(50,50); polygon(100, 4); polygon(100, 5); ;;; Save the old coordinate transformation procedure (in case it is ;;; wanted later). It transforms user coordinates to window ones. vars oldxyout = rc_transxyout; ;;; Set the new transformation procedure to do rotations rc_rotate_xy -> rc_transxyout; ;;; Set the frame angle to 0, i.e. lined up with screen 0 -> rc_frame_angle; ;;; now rotate coordinate frame 90 degrees counter-clockwise rc_rotate_frame(90); ;;; And re-draw the picture made of two polygons, using same parameters polygon(100, 4); polygon(100, 5); ;;; rotate The frame some more rc_rotate_frame(45); ;;; And re-draw again polygon(100, 4); polygon(100, 5); ;;; and again rc_rotate_frame(45); polygon(100, 4); polygon(100, 5); ;;; re-set to zero rotation by assigning directly to the active variable ;;; rc_frame_angle 0 -> rc_frame_angle; ;;; Watch the effect of a 180 degree rotation rc_start(); polygon(100, 4); polygon(100, 5); 180 -> rc_frame_angle; polygon(100, 4); polygon(100, 5); ;;; restore the frame angle 0 -> rc_frame_angle; -- Using the mouse to draw a picture "by hand" ------------------------ ;;; Now use the mouse to draw a picture lib rc_mouse; ;;; load the mouse package rc_start(); ;;; set it up to trap button presses in the window ;;; Draw a picture by repeatedly pressing mouse button 1 or 2 in the ;;; graphic window and terminate picture by pressing mouse button 3 ;;; "false" below means don't list the points. (If you are using a ;;; Hewlett Packard workstation and your mouse has only two buttons, ;;; the left one should be button 1 and the right one button 3. For ;;; "button 2" you need to press both buttons! Such details may be ;;; different on different terminals.) rc_mouse_draw(false, 3); ;;; NB terminate picture with button 3 When you do this it should show you a moving line from where you last pressed a button to where the mouse pointer is. I.e. there's a "rubber" band between the last fixed point and the mouse. If this rubber band is not visible, you may have to alter the "function" used to do the rubber-band drawing. E.g. if you are using a colour display, or an NCD X terminal or a Hewlett Packard workstation, try marking and loading the following GXequiv -> rc_rubber_function; Then re-do the above rc_mouse_draw command. Compare the effect of GXxor -> rc_rubber_function; which is the default. ;;; Now draw a different picture, and return a list of pairs of numbers ;;; giving points at which mouse pointed (first argument true), ;;; terminated when button 1 is pressed. The -true- means make a list ;;; of the points coordinates of the vertices in the picture. rc_start(); rc_mouse_draw(true, 1) ==> ;;; NB terminate picture with button 1 ;;; The list of points is printed out by ==>. Each point is produced by ;;; calling rc_conspoint with two arguments. rc_conspoint has the value ;;; conspair, but can be redefined, as long as rc_destpoint is also ;;; redefined (default is destpair). See HELP * RC_GRAPHIC/rc_conspoint -- Changing the colour used to draw with ------------------------------ If you are using a colour display, you can repeat the above drawing commands with colour changed as follows: XpwSetColor(rc_window, 'red'); XpwSetColor(rc_window, 'green'); XpwSetColor(rc_window, 'black'); For more information see REF * XpwCore, * XpwPixmap, * XpwGraphic -- Saving a picture drawn with the mouse, and re-drawing it ----------- ;;; Declare a variable to hold a list of picture points vars picpoints; ;;; Now draw a picture and save the coordinates in picpoints rc_start(); rc_mouse_draw(true, 3) -> picpoints; ;;; NB terminate with button 3 ;;; Define a procedure to re-draw a picture from a list of points, ;;; using a specified line_width define drawpic(pointlist, rc_linewidth); lvars pointlist, point; dlocal rc_linewidth; ;;; Must use dlocal - its an active variable ;;; Don't use vars ;;; Jump to the first point rc_jumpto(front(pointlist)); ;;; Draw the successive following points for point in pointlist do rc_drawto(point) endfor enddefine; ;;; Mark and load that procedure then test it on the list picpoints ;;; created above rc_start(); drawpic(picpoints, 0); ;;; 0 is the minimum linewidth. Compare 1 rc_start(); drawpic(picpoints, 1); ;;; Clear the picture, and draw it upside down with a thicker width rc_start(); 180 -> rc_frame_angle; drawpic(picpoints, 5); ;;; Now the right way up again, with an even thicker line rc_start(); 0 -> rc_frame_angle; drawpic(picpoints, 10); -- Example of use of rc_drawgraph ------------------------------------- A library program for drawing graphs is provided as an extension to lib rc_graphic. An example of its use follows. ;;; Load the library lib rc_drawgraph ;;; Define a procedure that corresponds to a parabola for each ;;; valueof x0 and r define testproc(x, x0, r); ;;; x0 and r will be partially applied, to give different parabolas ;;; y = r*x*(x0 - x) lvars x,r; r*x*(x0 - x) enddefine; ;;; Start or clear the window rc_start(); ;;; Set coordinate frame with origin at bottom left of window, ;;; with window bounds each corresponding to 1 unit. rc_set_coordinates( 0, rc_window_ysize, rc_window_xsize, -rc_window_ysize ); ;;; Draw the graph with x0 = 1, and r = 2.3, ;;; I.e. y = 2.3*x*(1 - x) rc_drawgraph(0,1,0,1,0.1,0.1,0.02,0.02,0.05, testproc(%1,2.3%)) => ;;; Note that rc_drawgraph returns the minimum and maximum values for ;;; y, in case you want to change the x bounds. ;;; The format for rc_drawgraph, explained in HELP RC_GRAPHIC is ;;; rc_drawgraph(xmin,xmax,ymin,ymax,xstep,ystep,xline,yline,xincr,fun) ;;; -> minyvalue -> maxyvalue ;;; Change origin to middle of window, and halve the scale. rc_set_coordinates (rc_window_xsize / 2.0, rc_window_ysize/2.0, rc_window_xsize/2.0, -rc_window_ysize/2.0); ;;; use rc_clear_window to clear the window without re-setting ;;; origin and scale rc_clear_window(); ;;; draw a new graph: y = 2.3*x*(0.5 - x) rc_drawgraph(-1,1,-1,1,0.1,0.1,0.02,0.02,0.05, testproc(%0.5,2.3%)) => ;;; draw y = 3*x*(0.6 - x), superimposed on the above rc_drawgraph(-1,1,-1,1,0.05,0.05,0.02,0.02,0.05, testproc(%0.6, 3%)) => -- A more sophisticated graph drawing package ------------------------- This package, providing far more options for drawing graphs, is described in TEACH * RC_GRAPHPLOT HELP * RC_GRAPHPLOT -- Using more than one window ----------------------------------------- LIB * RC_CONTEXT enables different windows to be created and to save the current context, switch to a different window by restoring its context, then switch back to the original. For details see HELP * RC_GRAPHIC/RC_CONTEXT -- Further reading ---------------------------------------------------- The facilities described above are described in more detail in HELP * RC_GRAPHIC Further facilities are described in TEACH * RC_GRAPHPLOT HELP * RC_GRAPHPLOT To see how they were defined: SHOWLIB * RC_GRAPHIC, * RC_ROTATE_XY, * RC_MOUSE, * RC_DRAWGRAPH SHOWLIB * RC_GRAPHPLOT, * RC_GRAPHPLOT2 TEACH * Xpw Examples of use of more basic X facilities TEACH * OPENLOOK A tutorial on using OLIT TEACH * MOTIVE A tutorial on using the Motif widget set HELP * X A general introduction to Poplog X facilities. HELP * Xpw An overview of the Poplog Widget Set REF * XpwCore * XpwPixmap * XpwGraphic Gives information about additional graphics and text facilities, including "raster" operations, etc. REF * XPOPINDEX A list of REF files available for X HELP * XPOPINDEX A list of HELP files available for X TEACH * XPOPINDEX A list of TEACH files available for X --- C.x/x/pop/teach/rc_graphic --- Copyright University of Sussex 1991. All rights reserved. ----------