Search                        Top                                  Index
TEACH GSTART                                    Aaron Sloman,  Oct 1996
                             (Based on a suggestion from Sophia Langley)


Getting started with Pop-11 via graphical programming, using procedures
from LIB RC_GRAPHIC, especially:

    rc_start();
    rc_draw(number);
    rc_turn(number);
    rc_jumpto(x, y);
    rc_drawto(x, y);

These form a powerful collection of primitives for making pictures
composed of lines. They provide a rapid introduction to a collection of
facilities in Pop-11, including procedure definitions, looping
constructs, interactive programs, and list processing,

         CONTENTS - (Use <ENTER> g to access required sections)

 -- Prerequisites
 -- What you will learn
 -- The procedures you will create
 -- Starting up, using the rc_graphic saved image
 -- Put your graphical procedures in a special file
 -- Put a definition of procedure rc_square into your file
 -- Defining square_picture
 -- Experimenting with square_picture
 -- Defining rc_polygon
 -- Defining locate_poly
 -- Joining up a list of points.
 -- Defining procedure rc_joinpoints
 -- Defining rc_get_draw: interactive drawing
 -- Defining rc_drawpicture
 -- Extending rc_get_draw
 -- Further information

-- Prerequisites ------------------------------------------------------

Before working through this it is a good idea to have become familiar
with VED. Reading TEACH VEDPOP would help. You'll need to know, in
advance, how to mark a range, how to copy marked ranges from one file to
another.

-- What you will learn ------------------------------------------------

This file gives an introduction to Pop-11 via simple graphical
programming, using the RC_GRAPHIC package ("RC" stands for "relative
coordinates").

The material below will introduce the following.

o You will learn how to create a program file called 'graphic.p' which
contains definitions of Pop-11 procedures (in this case procedures for
drawing simple pictures), along with "commented out" test instructions
for those procedures, and additional comments describing the procedures.

o You will learn to use the editor to switch between three files:

    o your program file 'graphic.p'

    o the output file 'output.p' in which non-graphical output appears

    o this TEACH file.

o You will gain some experience of Pop-11 syntax, including procedure
definitions, loops, conditionals, declaration of local variables.

o You will learn some of the basics of list processing in Pop-11 (but
not very much.)

o You will meet the Pop-11 pattern matcher

o You will learn a subset of the Pop-11 graphical facilities for use
with the X window system.

o You will get an introduction to interactive programming using the
procedure readline.


Most of the relevant features of Pop-11 are summarised in the online
summary file TEACH POPCORE (also available in printed form), and in text
books on Pop-11, as well as TEACH PRIMER, which is available in printed
form from the school library, either for purchase or on loan.

-- The procedures you will create -------------------------------------

Initially you will define the following procedures
rc_square(side);
    Draw a square whose side is of the given length.

square_picture(size1, size2);
    Draw a picture made of several squares in different orientations,
    of two different sizes.

rc_polygon(len, num);
    Draw a regular polygin with side len, with num sides.

locate_poly(xloc, yloc, startorient, len, num);
    Draw a polygon in a specified location with a specified
    orientation.

rc_get_draw();
    Define a procedure that reads in coordinates from the user, and
    draws lines joining up those points.


-- Starting up, using the rc_graphic saved image ----------------------

This section is relevant if you are reading this file in a printed
format. If you are reading it in VED you should already have been
through the steps described in this section.

The basic Poplog image in Birmingham now includes the rc_graphic
library, so the programs will start up quickly.

At other sites there may be a saved image which you can run to avoid
having to compile the rc_graphic library. E.g. if it is called
rc_graphic.psv in one of the standard saved image directories you can
start it up with the command (to Unix):

    pop11 +rc_graphic

Then when you get the Pop-11 prompt ":" give the command

    teach gstart

to get this teach file into VED.

At Birmingham in the School of Computer Science, or on sun1, just type,
to Unix:

    pop11

then, to Pop11:

    teach gstart

-- Put your graphical procedures in a special file --------------------

Create a file called graphic.p      (As explained in TEACH VEDPOP).

Put some comments between the comment brackets "/*" and "*/" at the
top of the file, saying what the file is about.

E.g. something like this

-----------------------------------------------------------------------
/*

File:   graphic.p
Author: Eve G. Eden
Purpose:
    This file contains definitions of some simple Pop-11 procedures
    for use with the library package RC_GRAPHIC.
    It also contains some test commands between comment brackets so that
    they are not automatically obeyed every time the file is compiled.

*/
-----------------------------------------------------------------------

In your file also put the following Pop-11 commands, after the comment.

-----------------------------------------------------------------------
uses rc_graphic         ;;; This will load RC_GRAPHIC only if necessary

false -> popradians;    ;;; Make sure angles are measured in degreees
                        ;;; Not radians
-----------------------------------------------------------------------

Note that the bits following ";;;" are ignored by Pop-11. They are
"end of line" comments.


-- Put a definition of procedure rc_square into your file -------------

After the previous commands insert the following procedure definition
into your graphic.p file.

When the procedure is run it will draw a square of a given side, using
the library procedures
    rc_draw (which takes a number representing a length)
    rc_turn (which takes a number representing an angle, in degrees)

-----------------------------------------------------------------------
define rc_square(side);
    ;;; <insert a comment here>
    lvars side;
    repeat 4 times
        rc_draw(side);
        rc_turn(90);
    endrepeat
enddefine;
-----------------------------------------------------------------------

Then load (compile) that procedure as follows.

    1. Put VED the cursor somewhere inside it
    2. do:      ENTER lcp RETURN

There are two shortcut alternatives to load a procedure:

    o Put the VED cursor in the procedure and type or ESC c

    o Use the CompileProc option on the Compiling menu
        (If you use VED's menus.)

If you get an error message when you compile the procedure that means
you have made some sort of "syntactic" mistake. If you correct it just
repeat the load command.

Then create some test commands between comment brackets in your
graphic.p file.

-----------------------------------------------------------------------
/*
;;; start or clear the graphic window
rc_start();

;;; draw two squares
rc_square(50);
rc_square(100);

;;; do the same at a different part of the picture
rc_jumpto(-150, -150);
rc_square(50);
rc_square(100);

;;; Do the same after rotating through an angle of 45 degrees
rc_turn(45);
rc_square(50);
rc_square(100);
;;; Do the last three commands again several times more

*/
-----------------------------------------------------------------------

After putting all those test commands into your graphic.p file,
run each test in turn, as follows (to run the "loadline" VED command)
    1. Put the VED cursor on the line of the command
    2: do ESC d

An alternative to step 2 is to use the "CompileLine" menu option.

You can try varying the commands in the previous test examples, and
then redo them. E.g. try changing the numbers, and see what happens.

Note: it is not necessary to define the procedure with a name beginning
"rc_". However by using the convention that all your graphical programs
use identifiers that start with a certain prefix you reduce the risk
that later on you will want to use the same name for another procedure,
and then discover a clash of names.


-- Defining square_picture --------------------------------------------

If you wish to define a procedure to create a picture made of two sizes
of squares drawn at 8 orientations you can do the following. Put this
procedure at the end of your graphic.p file, followed by some test
commands in comment brackets.

-----------------------------------------------------------------------

define square_picture(size1, size2);
    ;;; Draw a picture made of 8 big squares and 8 small squares
    ;;; at 8 different orientations
    lvars size1, size2;
    repeat 8 times
        rc_square(size1);
        rc_square(size2);
        rc_turn(45);
    endrepeat
enddefine;

/*
;;; Tests for the above procedure
rc_start();     ;;; clear the picture

square_picture(150, 50);

square_picture(100, 25);

;;; clear and start again
rc_start();     ;;; clear the picture
square_picture(150, 50);

;;; Now turn left 22.5 degrees, and repeat
rc_turn(22.5);
square_picture(150, 50);

*/
-----------------------------------------------------------------------

-- Experimenting with square_picture ----------------------------------

You might like to try extending that last example with a turn of 11.25
degrees, and see what the result looks like.

You could also try different sizes for the big and small squares, e.g.
something like this
-----------------------------------------------------------------------
/*
    rc_start();
    vars big, small;
    for big, small in [160 120 80 40], [75 55 35 15] do
        square_picture(big, small);
        rc_turn(45)
    endfor;

*/
-----------------------------------------------------------------------
In order to run that test you can mark and load the whole thing. First
mark from the "vars" line to the "endfor" line. Then to load (compile)
the marked range do

    ENTER lmr RETURN

or, choose the "CompileRange" button from the "Compiling" menu.
It's probably a good idea to clear the graphic window first.

Try it again with different numbers in the lists and see if you can
work out what's going on.

The bit between for and endfor is a loop. The two variables, big and
small, take successive values from the list, one from each list. Thus
initially their values are 160 and 75, then 120 and 55, and so on.


-- Defining rc_polygon ------------------------------------------------

Now define a procedure to draw a polygon of side len, and with num
sides as follows and put it into your file graphic.p

For the picture to "close up" you have to turn through an angle after
each side, where the angle must be chosen so that after num turns it
gets back to the original orientation, i.e. the total rotation after num
turns is 360 degrees. So in each turn the rotation is 360/num

-----------------------------------------------------------------------
define rc_polygon(len, num);
    ;;; <You put a comment in here>
    lvars len, num;
    ;;; work out the external angle to turn after drawing each side
    lvars ang = 360/num;

    repeat num times

        .... you fill in this bit using rc_turn and rc_draw .....

    endrepeat
enddefine;

/*
rc_start();

rc_polygon(100,4);

rc_polygon(100, 5);

rc_polygon(35, 15);
*/
-----------------------------------------------------------------------
Add some additional tests, and make sure that your procedure does
what you expect.

HINT:
If you had trouble completing the definition of rc_polygon, all that
was needed to replace the line with dots was these two lines.

    rc_draw(len);
    rc_turn(ang);

If you could not make it work, try inserting those two, then compile and
test the procedure.

-- Defining locate_poly -----------------------------------------------

Now try to extend that to start drawing a polygon in a given location
and at a given orientation.
-----------------------------------------------------------------------

define locate_poly(xloc, yloc, startorient, len, num);
    ;;; Draw a polygon at position with coordinates xloc, yloc,
    ;;; where each side is if size len, and there are num sides,
    ;;; and the first side is drawn at an angle of startorient with
    ;;; the horizontal.

    lvars xloc, yloc, startorient, len, num;

    rc_jumpto(xloc, yloc);
    startorient -> rc_heading;      ;;; set the initial heading

        .... use rc_polygon  to complete the definition....

enddefine;
-----------------------------------------------------------------------

All you have to do to complete the definition is replace the line with
dots. Use the procedure defined previously.

Add some tests between comment brackets, such as

    locate_poly(-100, 0, 270, 100, 4);

and others with different numbers.

HINT:

If you had trouble completing that procedure, replace the line with
dots with the following:

    rc_polygon(len, num)


-- Joining up a list of points. ---------------------------------------

In the example using the for ... endfor loop above we used two lists of
numbers, one for the succession of big square sizes and one for the
succession of small square sizes. If we wanted to draw lines joining up
a list of points given by their x and y coordinates it would be useful
to be able to keep the x and y coordinates together, instead of having
them in separate lists. We could then define a picture by a list
of points represented by a list of two-element lists of coordinates,
such as

    [ [0 0] [10 0] [10 20] [-20 20] [-20 -40] [40 -40] ]

We could then use something like the following format

    for point in list_of_points do
        <draw line to point>
    endfor

The procedure rc_drawto nearly does what we want. Try the following
commands in turn:

    rc_start();
    rc_jumpto(0, 0);
    rc_drawto(10, 0);
    rc_drawto(10, 20);
    rc_drawto(-20, 20);
    rc_drawto(-20, -40);
    rc_drawto(40, -40);

If you try to apply rc_jumpto or rc_drawto to a list of two numbers you
will get an error (or "mishap" in Pop-11). Try it

    rc_drawto([40 40]);

The following will appear in your output.p file.

;;; MISHAP - NUMBER(S) NEEDED
;;; INVOLVING:  [] -1
;;; DOING    :  mishap * rc_transxyout rc_drawline rc_drawto .....

Don't worry about where the empty list and the -1 come from. It's a long
story. What the "DOING" line tells you is that rc_drawto gave some
information to rc_drawline and that gave some information to
rc_transxyout, and that tried to do a multiplication (i.e. the asterisk)
and that found that it did not have two numbers to multiply.

(Arguably, the procedure rc_drawto should have checked that it had the
right format before calling rc_drawline. The reason it does not check is
that it can handle Pop-11 objects called "pairs" and lists are made of
pairs. But the full story is complicated and will not be given here.)

Anyhow, if we can get the numbers out of the list before giving them to
rc_drawto then all should be well. Fortunately Pop-11 has a procedure
called explode. Try loadline on this

    explode([1 2 3 4]) =>

it should print the following in the output.p file

    ** 1 2 3 4

What this means is that the explode command produce a multiple result
consisting of the four numbers, and the Pop-11 print arrow "=>" printed
them all out. The numbers were left on the Pop-11 "stack", and "=>"
prints out everything on the stack.

Equally a procedure that requires two numbers can get them from the
stack. For example:

    explode([40 40]);   ;;; put the elements of the list on the stack

    rc_drawto();        ;;; given no inputs, so take two numbers from
                        ;;; the stack.

If you do those two commands separately in VED the items on the stack
will be cleared after the first command. We can combine them thus:

    rc_drawto( explode( [40 40] ) );

    rc_drawto( explode( [-40 40] ) );

    rc_drawto( explode( [-40 -60] ) );

Try each of those commands.

Now try the following:

    vars pointlist = [[0 0] [10 0] [10 20] [-20 20] [-20 -40] [40 -40]];

That declares the global variable pointlist, and initialises it with a
list of lists as values. You can print out the value thus:

    pointlist =>

That should print out in the output.p file as

    ** [[0 0] [10 0] [10 20] [-20 20] [-20 -40] [40 -40]]

Now try marking and loading the following:

    rc_start();
    vars point;
    for point in pointlist do
        rc_drawto( explode(point) );
    endfor;

There is a slight problem remaining. The first point in the list given
above was the centre of the window, namely the point [0 0]. That also
happens to be the location at which the drawing will start after the
window is cleared by rc_start(); If you had a pointlist that started
from some other location the initial call of rc_drawto would draw a line
from point 0,0 to that other location. Ideally we want that not to
happen. So we need to get the graphic program JUMP to the first point,
then DRAWTO all of the remaining points. You can get the first element
of a list using the Pop-11 procedure called "hd" for "head", and get a
list of all the remaining elements by using the Pop-11 procedure called
"tl" for "tail". Try using them as follows:


    rc_start();
    vars pointlist =
        [[-10 0] [0 0] [0 10] [10 10] [10 20] [20 20] [20 30] [30 30]];

    vars point;
    rc_jumpto(explode(hd(pointlist)));  ;;; jump to first location

    ;;; now draw to all the others in tl(pointlist)
    for point in tl(pointlist) do
        rc_drawto( explode(point) );
    endfor;


-- Defining procedure rc_joinpoints -----------------------------------

You now have all the information required to define a procedure with the
following features

    1. It is to be called rc_joinpoints
    2. It takes one input, called points, which is a list of two-element
       lists representing points by their coordinates,
    3. It uses rc_jumpto to jump to the first point,
    4. It uses rc_drawto to draw to all the rest (using explode)

Define such a procedure in your graphic.p file. Test it with a list
of points making up a square with a triangular "roof".

-- Defining rc_get_draw: interactive drawing --------------------------

If you want to create a procedure that reads in sets of points from
the user and then draws them, try something like the following, using
the readline procedure to get the information from the user:

define rc_get_draw();
    lvars firstpoint, next;

    lvars xloc, yloc;    ;;; pattern variables used below

    repeat
        'Please type in the starting point' =>
        readline() -> firstpoint;
        if firstpoint matches ! [?xloc ?yloc] then
            rc_jumpto(xloc, yloc);
            quitloop();
        else
            ;;; format wrong, try again
            'Wrong format, please type in two numbers' =>
        endif;
    endrepeat;

    ;;; now repeatedly get remaining points, till user types "bye"
    repeat
        'Type "bye" to quit, or "close" to close figure and quit' =>
        'or type two numbers' =>
        readline() -> next;
        if next = [bye] then
            'finished' =>
            quitloop();
        elseif next = [close] then
            rc_drawto(explode(firstpoint));
            'picture closed up now' =>
            quitloop();
        endif;


        until next matches ! [?xloc ?yloc] do
            'Wrong format. Please just two numbers, or "bye" or "close"' =>
            readline() -> next;
        enduntil;
        rc_drawto(xloc, yloc);

    endrepeat;

enddefine;

Note: the "!" after "matches" is an operator that transforms patterns
containing "?" or "??" so that the variables in such patterns are common
with lvars in the procedure. Otherwas they would have to be declared as
"vars". (See HELP LVARS).

Now test it
/*
rc_start();
rc_get_draw();

*/


-- Defining rc_drawpicture --------------------------------------------

Define a procedure called rc_drawpicture that takes a list of lists of
lists, and for each of the lists of lists uses rc_joinpoints to joinup
the points in that list. For example, rc_drawpicture could be applied to
the list
    [
        [[10 0] [0 100] [100 100] [10 0]]
        [[0 10] [100 0] [-100 100] [0 10]]
        [[-10 0] [0 -100] [-100 -100] [-10 0]]
    ]

To make a picture formed from three connected sub-pictures.


-- Extending rc_get_draw ----------------------------------------------

A problem with the interactive procedure rc_get_draw is that it
can only draw connected pictures as it goes on joining up points
until you type "bye" or "close".

Modify the procedure rc_get_draw so that if the user types in "new"
the procedure then asks for a new point to start drawing a new
sub-picture, and uses rc_jumpto instead of rc_drawto, to get to that
point.

-- Further information ------------------------------------------------

If you want to find out more about the graphical facilities for drawing
pictures see
    TEACH * RC_GRAPHIC
        for a tutorial introduction
    HELP * RC_GRAPHIC
        for a more compressed summary

Overviews of Pop-11
    TEACH * POPCORE
        for a summary of some of the main features of Pop-11
    TEACH * PRIMER
        for a very full overview of Pop-11 (available in printed form)

The following files introduce lots more features of Pop-11
    TEACH * STACK
        for a tutorial on the Pop-11 stack
    HELP * DEFINE
        for more on the syntax of procedure definitions
    HELP * IF
        overview of conditionals in Pop-11
    HELP * FOR
        more on the options available with "for... endfor"
    HELP * LOOPS
        more on loops in Pop-11
    HELP * CONTROL
        different control mechanisms in Pop-11
    TEACH * LISTS, * ARROW
        tutorial introduction to list processing
    TEACH * MATCHES, * MATCHARROW, * MOREMATCH, HELP * MATCHES
        tutorial introductions to the Pop-11 matcher
    HELP * OBJECTCLASS, TEACH * OBJECTCLASS_EXAMPLE, * ADVENT_OBJECTCLASS
        introduction to object oriented programming
    HELP * LVARS, * VARS, * LEXICAL, * DLOCAL
        more technical aspects of local and non-local variables and
        procedure entry and return
    HELP * POPUPTOOL
        explains a simple tool for menu-driven interfaces
    TEACH * VED_MENU, HELP * VED_MENU
        explains how to extend the VED control panels
    TEACH * PROPSHEET
        describes a far more sophisticated interface design tool,
        with menus, sliders, text fields, etc. (Not easy to use).
    HELP * DATABASE, TEACH * DATABASE, TEACH * FOREACH, HELP * FOREACH,
    HELP * FOREVERY, HELP * WHICH
        Introductions to the Pop-11 database mechanism (based on the
        matcher)
    TEACH * RULEBASE
        Introduces one of several expert system shells in Pop-11
    TEACH * EXPERTS
        Introduces three different shells (mycin, prospector, eshell)
    TEACH * RECURSE1 * RECURSE2 * RECURSE3
        Introduction to recursion of various kinds
    TEACH * SETS * LISTQUESTIONS * SETS2
        Progressive exercises on list processing and set manipulation
    TEACH * ARITH, * DECIMALS HELP * MATH
        For mathematical facilities in Pop-11
    TEACH * READLINE, * RESPOND
        Introduction to interactive programs using readline
    TEACH * SECTIONS
        For breaking up your program into sections in such a way as to
        prevent identifier clashes between sections.

Other topics available
    More general introductions to the X interface in Poplog
    How to simulate or invoke Prolog from Pop-11
    How to create and use saved images (with code already compiled)
    How to link in external procedures (C, Fortran).
    How to extend the syntax of Pop-11 with new constructs
    How to interface with the operating system (Unix).
    File manipulation procedures.
    How to do discrete event simulation.
    How to use the Pop-11 "process" mechanism, e.g. to simulate an
        operating system or other concurrent process
    How to define new data types (vector classes and record classes0
    Various kinds of N-dimensional arrays in Pop-11
    Hash-linked tables in Pop-11 (properties)
    How to program VED or (XVED).
    How to implement new languages in Pop-11.
    Parsing procedures.
    Image processing.

--- $poplocal/local/teach/gstart
--- Copyright University of Birmingham 1996. All rights reserved. ------