Bottom     Previous     Contents

CHAPTER 1
Turtle Graphics

There is
one art,
no more,
no less:
to do
all things
with art-
less ness

Piet Hein, Ars brevis

In Mindstorms, Seymour Papert (1980 : 219) gives a short BASIC program to draw a house. Converted to BB, this little program is

1000 MOVE 0,0
1010 DRAW 100,0
1020 DRAW 75,150
1030 DRAW 0,100
1040 DRAW 0,0
1050 END

and Papert notes that this is not suitable as a general method for drawing a house, for it also requires quite a good deal of work to prepare. "This demand would be less serious if the program, once written, could become a powerful tool for other projects . . . the BASIC program allows one particular house to be drawn in one position. In order to make a BASIC program that will draw houses in many positions, it is necessary to use algebraic variables. . ."
Papert proves his own point (perhaps deliberately) by giving a routine for drawing a lopsided house -- try the program to see.
How is the house constructed? Essentially the house is a square (or rectangle) with a triangle on top: forget about inessential aspects such as doors and windows for the moment. To draw a house, therefore, we draw a square, and place the triangle on top. Start with the square. Let our square be of side SIDE, and let it be drawn from any arbitrary coordinate X,Y: make it into a procedure.

1000 DEF PROCL-SQUARE(X,Y, SIDE)
1010 PLOT 0,X,Y : REM MOVE TO X, Y
1020 PLOT 1,SIDE,0 : REM A RELATIVE PLOT
1030 PLOT 1,0,SIDE
1040 PLOT 1,-SIDE,0
1050 PLOT 1,0,-SIDE : REM BACK TO BASE
1060 ENDPROC : REM SQUARE COORD VERSION 1

As you will note, I have used 'relative' plots in constructing the routine (UG page 319), partly because it means that we only refer to X and Y at one point. Suppose that the graphics cursor was already at the point X, Y? We can ignore line 1010, and treat X and Y as global to the procedure (really we never have to refer to X or Y):

1000 DEF PROC_SQUARE(SIDE)
1010 PLOT l,SIDE,0 : PLOT 1,0,SIDE
1020 PLOT 1,-SIDE,0 : PLOT 1,0,-SIDE
1030 ENDPROC : REM SQUARE COORD VERSION 2

lines 1010 then become similar. PROC_SQUARE can be prettified

1000 DEF PROC_SQUARE (SIDE)
1010 PROC LSHAPE (SIDE) : PROC_LSHAPE(-SIDE)
1020 ENDPROC : REM SQUARE COORD VERSION 3
1025
1030 DEF PROC_LSHAPE (LIMB)
1040 PLOT 1,LIMB,0 : PLOT 1,0,L1MB
1050 ENDPROC : REM LSHAPE (by Lynne Reid Banks?)

and we now have two routines where once there was one. The second routine (ie PROC_LSHAPE) could be used for other shapes, other than the square: PROC_LSHAPE could become part of a library of 'useful routines' but really there is little point to the exercise. PROC_LSHAPE is not exactly memorable: can you remember which way it bends, and could you remember it in aeons to come, together with many other little gobbets of program?

How are we to tilt the house? How are we even to tilt the LSHAPE?

Intrinsic geometry

To draw a square we go forward a fixed distance and turn left (or fight) through 90 degrees. This we do four times: why not draw a square in this way? There seems to be an internal logic to a square, which does not depend upon sides being horizontal and vertical.
A geometrical figure, such as a square, has a certain 'intrinsic' property, which depends only upon that type of figure: that a square has four equal angles, and four equal sides, is independent of position and orientation. To say that the sides of a square must be parallel to the axes (as in the above routines) is an 'extrinsic' property: an external frame of reference is needed to decide which direction is horizontal.
Rather than concentrating on external properties, which is what one has to do if one concentrates on coordinates and transformations of coordinates, the routines herein concentrate upon the intrinsic properties of shapes. As Piet Hein implies, simplicity is the way to true art ('Ars brevis' means 'Art in short').
A procedure:

1000 DEF PROCL-SQUARE (SIDE)
1010 LOCAL I : FOR I=1 TO 4
1020 PROC_MOVE(SIDE,I) : PROC_TURN(90)
1030 NEXT I
1040 ENDPROC : REM SQUARE INTRINSIC VERSION

which uses two other procedures PROC_MOVE and PROC_TURN, of which more later. To draw a square of side 100, instantly we have to enter.

PROC_SQUARE(100)

where the square is drawn at the current cursor position. Highly complex shapes can be produced by use of a very few essential procedures. Design a procedure to draw an equilateral triangle:

1100 DEF PROC_TRIANGLE(SIDE)
1110 LOCAL I : FOR I = I TO 3
1120 PROC_MOVE(S1DE,1) : PROC_TURN(l20)
1130 NEXT I
1140 ENDPROC : REM TRIANGLE INTRINSIC VERSION

and it is simplicity itself. We can draw a triangle in exactly the same way as we drew the square, entering

PROC_TRIANGLE(SIDE)

then to tilt the square through 25 degrees counter clockwise

PROC_TURN(25) : PROC_SQUARE(l00)

in instant mode. To move to coordinates 20,250 (without plotting) and then draw a square turned through 43 degrees counter clockwise

PROC_MOVETO(20,250,0): PROC_TURN(43):
PROC_SQUARE(100)

- no calculation whatever, purely a concentration on the intrinsic nature of the problem. Note that in PROC_MOVE and PROC_MOVETO the final parameter is 1 for plot; and 0 for do not plot, just move.
One last example:

1200 DEF PROC_QUIZ(SIDE)
1210 LOCAL I : FOR I = I TO 6
1220 PROC_MOVE(SIDE) : PROC_TURN(60)
1230 NEXT I
1340 ENDPROC : REM QUIZ - GUESS WHAT

to whet your analytical appetite.

Turtle geometry

The above form of analysis, which concentrates on intrinsic properties of geometrical figures, is commonly called Turtle geometry. Papert's book, to which I earlier referred, is the classic text for explaining the reasons behind turtle geometry. The subtitle to Papert's book is 'Children, computers, and powerful ideas' and this has led some to believe that turtle geometry is 'kid's stuff', to be ignored, or left to little children.
This is not only wrong, but very short sighted: Turtle Geometry (Abelson and diSessa, 1980) is far beyond a child's picture book. Like any powerful methodology (or powerful computer language) the scope is vast: from the very simple (but never trivial) triangle to, eg, Lorentz transformations in relativistic mechanics. Turtle geometry is a powerful and accessible means of producing computer graphics which is not only creative but also of great utility.
Though using turtle graphics is a powerful tool, turtle graphics is also part of a philosophy and style of using computers. Two fundamental ideas which underlie much of the work in this book are:

It is possible to design procedures which make the communication with computers a more natural process than is possible with more traditional methods of programming graphics;
Learning to use graphics in this manner can assist in the learning of general thinking about program design -- by considering the intrinsic nature of the problem and not its merely extrinsic aspects.

Experience is an important element in learning how to perform any task, and the computer can assist tremendously in producing many varied forms of experience. Many of the procedures (eg PROC_INSPIRALI) produce results which surprise myself, so expect to be surprised.
The approach through turtle graphics, and similar styles of application, are not the old 'discovery methods' they used to practise at school. With discovery methods the teacher or author of the book is supposed to know what is to be discovered -- often the results of turtle routines are news to me as well.
In turtle graphics the user has control of a little (hypothetical) creature called a turtle, and the turtle fives on the surface of the visual display (TV or VDU). The turtle responds to a few very simple commands MOVE forward, and TURN through and angle (in the LOGO and SMALLTALK languages the commands are the same but differently named, see Papert, 1980, and Smalltalk-80 by Goldberg and Robson, 1983). The intrinsic routines PROC_SQUARE, PROC_TRIANGLE, and PROC_QUIZ could all be followed by a little turtle on the screen. Turtle geometry (eg constructing shapes by use of turtle(s)) is a useful alternative to traditional „ methods of 'doing graphics' -- this will become clearer as we progress.
At more advanced levels, in the geometry of curved surfaces (ie differential geometry), the turtle always faces and turns in the tangent plane of the point on the surface at which the turtle is located. As the geometry of space in Einstein's theory of relativity is a differential geometry, the turtle can explore Einstein's universe -- but we will not (for more details see Abelson and diSessa, 1980).

Turtle commands

The basic turtle commands are very few, a move command, and a turn command: theoretically these are all that are needed (a moveto command is not really necessary). The turtle commands I have implemented for Version 1.1 are -- apart from housekeeping commands -- the following:

PROC_TURN (A) Turn through A degrees

PROC_TURNTO(A) Turn to angle A degrees

PROC_MOVE(D,S) Move forward D units, S=1 to plot, S=0 to just move.

PROC_MOVETO(X,Y,S) Move to coords X,Y, S=1 to plot, S=0 to move

plus a command

PROC_LOC What are the coords, and what is the present angle?

However, to use these commands the screen needs to be organized in such a manner that text and graphics can be separated.

The screen housekeeping commands are:

PROC_START Clear the screen and set up separate text and graphics screens, centre cursor

PROC_RESTART Clear only the graphics screen and set the cursor to the centre

PROC_CENTRE Centre the cursor

PROC_INVERT Change the drawing colour from black to white or vica versa

But a program is worth a thousand words -- so enter in routines Turtle Graphics Version 1.1. I will then discuss the routines in the order in which they appear in the listing.

1000 REM-------------------------------

1010

1020

1030 REM G R A P H I C ART

1040

1050 REM (c) Boris Allen, 1983

1060

1070

1080 REM-------------------------------

1090

1100 REM Turtle Graphics : 1.1

1110

1120 REM-------------------------------

1130

1140 DEF PROC_CLRSCR

1150 PROC_CLS : PROC_CLG

1160 ENDPROC : REM CLRSCR

1170

1180 DEF PROC_CLG

1190 GCOL 0,PEN : GCOL 0,129-PEN

1200 VDU 24,0;128;1279;1023; : CLG

1210 REM Clears an upper graphics windo

w

1220 VDU 29,640;566;

1230 REM Sets the origin to centre of g

raphics window

1240 ENDPROC : REM CLG

1250

1260 DEF PROC_CLS

1270 COLOUR 1-PEN : COLOUR 128+PEN

1280 VDU 28,0,31,39,28 : CLS

1290 REM Clears lower text window

1300 ENDPROC : REM CLS

1310

1320 DEF PROC_COL(PE)

1330 PEN=PE

1340 ENDPROC : REM COL

1350

1360 DEF PROC_CENTRE

1370 MOVE 0,0 : ANGLE=0 : X=0 : Y=0

1380 ENDPROC : REM CENTRE

1390

1400 DEF PROC_RESTART

1410 PROC_CLG : PROC_CENTRE

1420 ENDPROC : REM RESTART

1430

1440 DEF PROC_START

1450 PROC_COL(0) : PROC_CLRSCR : PROC_C

ENTRE

1460 ENDPROC : REM START

1470

1480 DEF PROC_INVERT

1490 PEN=1-PEN : GCOL 0,PEN

1500 ENDPROC : REM INVERT

1510

1520 DEF PROC_TURNTO(A)

1530 ANGLE=FN_ANGLE(A)

1540 ENDPROC : REM TURNTO

1550

1560 DEF PROC_TURN(A)

1570 ANGLE = FN_ANGLE(ANGLE+A)

1580 ENDPROC : REM TURN

1590

1600 DEF PROC_LOC

1610 PRINT "COORDINATES ARE ";X,Y'"ANGL

E IS "ANGLE

1620 ENDPROC : REM LOC

1630

1640 DEF PROC_MOVE(DISTANCE,STYLE)

1650 X=X - DISTANCE*SIN(RAD(ANGLE))

1660 Y=Y + DISTANCE*COS(RAD(ANGLE))

1670 IF STYLE=1 THEN DRAW X,Y ELSE MOVE

X,Y

1680 ENDPROC : REM MOVE

1690

1700 DEF PROC_MOVETO(XN,YN,STYLE)

1710 LOCAL XDIF,YDIF : XDIF=XN-X : YDIF

=Y-YN

1720 IF YDIF<>0 THEN PROC_TURNTO(DEG(AT

N(XDIF/YDIF))+180*(YN<Y)) ELSE PROC_TURN

TO(SGN(-XDIF)*90)

1730 X=XN : Y=YN

1740 IF STYLE=1 THEN DRAW X,Y ELSE MOVE

X,Y

1750 ENDPROC : REM MOVETO

1760

1770 DEF FN_ANGLE(A)

1780 IF A MOD 360 <0 THEN =A MOD 360 +

360 ELSE =A MOD 360

1790 REM ANGLE

1800

1810 DEF PROC_NEW

1820 VDU 26 : CLS

1830 ENDPROC : REM NEW

1840

PROC_CLRSCR consists of two routines PROC_CLS and PROC_CLG, defined later.

PROC_CLG sets the graphics foreground and background colours by use of GCOL (UG page 262) and a global variable PEN. Usually the foreground is black and the background white. Line 1210 sets a graphics window (see above) and clears the graphics window; line 1220 sets the origin to the centre of the window.

PROC_CLS sets the text foreground and background colours (UG page 222) to the reverse of those normally set by PROC_CLG. A text window, for the lower four lines, is established and the text window is cleared.

PROC_COL is the first routine with a parameter, and is merely a way of altering the value stored in the global variable PEN. PEN normally has the value 0, but this allows that value to be changed procedurally (another way -- less consistent -- is PEN = PE).

PROC_CENTRE moves the cursor to the centre, and sets the global variables X,Y, and ANGLE all to zero.

PROC_RESTART clears the graphics window (PROC_CLG) and then centres the cursor (PROC_CENTRE) -- the text is unaffected. The global variable PEN is not affected.

PROC_START sets the PEN to zero, clears both screens (PROC_CLRSCR) and centres the cursor (PROC_CENTRE). This routine has to be activated before any of the others, otherwise some of the global variables might be uninitialized.

PROC_INVERT changes the foreground colour in graphics, without altering the background colour (black to white and vice versa). To alter the value from O to 1 (or vice versa) the value is subtracted from I. Another way of changing the value might be PROC_COL(1-PEN). This routine is used for erasing existing lines.

PROC_TURNTO sets the value stored in the global variable ANGLE to the value supplied. To make sure that values do not go outside the range 0 to 359, the value is normalized by FN_ANGLE. Not a true turtle command because it refers to an absolute (rather than relative) angle, the name of this command derives from UCSD Pascal (Bowles, 1977), as do most of the routine names herein.

PROC_TURN takes the value of the parameter, and adds it onto the global variable ANGLE, where counting of angles is in a counterclockwise direction and uses FN_ANGLE.

PROC_LOC is simply an environmental enquiry 'What is my location, and in which direction am I facing?' . In my turtle graphics procedures you cannot see the turtle, and so this is to help when lost.

PROC_MOVE has two parameters: the first (DISTANCE) gives the distance to be moved, and the second (STYLE) indicates whether there is to be a plot or a move (many versions of turtle graphics have PENUP and PENDOWN commands). The calculations in fines 1650 and 1660 need not detain us.

PROC_MOVETO is not a true turtle command, because it is absolute not relative taken from UCSD Pascal. The first two parameters are the coordinates, and the final parameter is the plotting style (comparable to PROC_MOVE). Do not bother about the calculations needed, except to notice that the IF in line 1720 is to trap a possible division by zero.

PROC_NEW returns both graphics and text windows to their full screen values, and both cursors are horned (see UG page 387).

FN_ANGLE constrains the angle between 0 and 359, and the conditional (in line 1780) is to account for negative as well as positive angles -- all negative angles become positive.

A square dance

As I have already noted, the only really essential commands are PROC_MOVE(DISTANCE,STYLE) and PROC_TURN(A): though the routines I shall discuss in the rest of this chapter make use of many of BB's facilities, they use only the basic two turtle commands. The routines are designed to operate in mode 4, though they will run under mode 0.
The routines are fisted as Turtle Routines 1.1, and the first to be examined will be that to draw a square. To draw a square we first draw the side of a square (ie PROC_SIDESQ), which -- as we have seen -- is move forward a distance and then turn through 90 degrees. The distance move forward corresponds to the parameter SIDE, and is the length of the side of the square.

2000 REM-------------------------------

2010

2020

2030 REM G R A P H I C ART

2040

2050 REM (c) Boris Allen, 1983

2060

2070

2080 REM-------------------------------

2090

2100 REM Turtle Routines : 1.1

2110

2120 REM-------------------------------

2130

2140 DEF PROC_SIDESQ(SIDE)

2150 PROC_MOVE(SIDE,1) : PROC_TURN(90)

2160 ENDPROC : REM SIDESQ

2170

2180 DEF PROC_SQUARE(SIDE)

2190 LOCAL I : FOR I=1 TO 4

2200 PROC_SIDESQ(SIDE) : NEXT I

2210 ENDPROC : REM SQUARE

2220

2230 DEF PROC_SQTURN

2240 LOCAL I,A$ : FOR I=1 TO 600

2250 PROC_MOVE(I,0) : PROC_SQUARE(I)

2260 PROC_TURN(30) :A$=INKEY$(0)

2270 IF A$="F" THEN ENDPROC ELSE NEXT I

2280 ENDPROC : REM SQTURN

2290

2300 DEF PROC_INSPIRALR(SIDE,ANG,INC)

2310 PROC_MOVE(SIDE,1) : PROC_TURN(ANG)

2320 PROC_INSPIRALR(SIDE,ANG+INC,INC)

2330 ENDPROC : REM INSPIRALR

2340

2350 DEF PROC_INSPIRALI(SIDE,ANG,INC)

2360 REPEAT

2370 PROC_MOVE(SIDE,1) : PROC_TURN(ANG)

2380 ANG = ANG + INC : A$ = INKEY$(0)

2390 UNTIL A$="F"

2400 ENDPROC : REM INSPIRALI

2410

2420 DEF PROC_CIRCLE

2430 LOCAL I : FOR I = 1 TO 360

2440 PROC_MOVE(1,1) : PROC_TURN(1)

2450 ENDPROC : REM CIRCLE

2460

2470 DEF PROC_PERIFIXED(PERIM,SIDES)

2480 LOCAL ANG,I

2490 ANG = 360/SIDES

2500 FOR I=1 TO SIDES

2510 PROC_MOVE(PERIM/SIDES,1) : PROC_TU

RN(ANG)

2520 NEXT I

2530 ENDPROC : REM PERIFIXED

2540

2550 DEF PROC_POLYGONS

2560 LOCAL I

2570 FOR I = 6 TO 36 STEP 6 : PROC_PERI

FIXED(1080,I)

2580 PROC_CENTRE : PROC_TURN(I*10) : NE

XT I

2590 ENDPROC : REM POLYGONS

2600

2610 DEF PROC_SNOWFLAKE(ODER,INC)

2620 PROC_DECISION(ODER,60,INC)

2630 PROC_DECISION(ODER,120,INC)

2640 PROC_DECISION(ODER,120,INC)

2650 ENDPROC : REM SNOWFLAKE

2660

2670 DEF PROC_DECISION(ODER,ANG,INC)

2680 PROC_TURN(ANG)

2690 IF ODER>0 THEN PROC_POINT(ODER-1,I

NC) ELSE PROC_MOVE(INC,1)

2700 ENDPROC : REM DECISION

2710

2720 DEF PROC_POINT(O,I)

2730 PROC_DECISION(O,0,I)

2740 PROC_DECISION(O,-60,I)

2750 PROC_DECISION(O,120,I)

2760 PROC_DECISION(O,-60,I)

2770 ENDPROC : REM POINT

2780

2790 DEF PROC_OUTSPIRAL(A,INC)

2800 LOCAL I,A$

2810 PROC_CENTRE : REPEAT

2820 PROC_TURN(A) : PROC_MOVE(I,1) : I

= I + INC

2830 A$=INKEY$(100) : UNTIL A$="F"

2840 ENDPROC : REM OUTSPIRAL

To draw a square we have to draw four sides, which is just what PROC_SQUARE does. The loop counter (I) is declared as being local to the procedure, as it is only operative within that procedure. Another way of writing the procedure would be on the one fine, say. Now to use PROC_SQUARE.
First, we clear the decks for action by setting up the special text and graphics screens, and, second, we draw the square (of side 200):

PROC_START : PROC_SQUARE (200)

We enter this interactively, and see a square (almost) instantly appear. To draw a bigger square, tilted through 50 degrees, keeping the first square on screen:

PROC_TURN(50) : PROC_SQUARE(300)

a tilted square appears. Try

PROC_TURN(-100) : PROC_SQUARE(300)

and a similar larger square will appear -- tilted in the opposite direction (50 - 100 = -50). Now clear the graphics, keep the text, and move the square away from the centre:

PROC_RESTART : PROC_MOVE(l00,0)
PROC_SQUARE(200)

and it is worth entering the two lines separately.
The latter two lines will: (a) clear the graphics screen; (b) move 100 units in a upwards direction -- without plotting; and (e) draw a square of side 200 units at that point. Note the different effect.

PROC_RESTART : PROC_TURN(160) : PROC_MOVE(200,0)
PROC_SQUARE(200)

produces (a tilted square, bottom leftish). Finally, try

PROC_RESTART : PROC_MOVETO(200,-300,0)
PROC_SQUARE(200)

to see how it is possible to use non-basic turtle commands. Try to let the squares dance by using PROC_SQTURN.
In this routine I and A$ are local to the procedure: I is used as a loop counter, and A$ is used as a means to produce early termination (the F key is pressed). For up to 600 times the cursor (or turtle) moves forward a distance I (without drawing), draws a square of side I, and then the turtle turns through 30 degrees. The keyboard is checked by INKEY$(0) to see if a key is pressed (saved in A$); if the key was an F, then ENDPROC else the loop counter is incremented.
The routine is activated by

PROC_RESTART : PROC_SQTURN

and it runs remarkably quickly. If you want to slow it down, put a pause in the INKEY$, eg INKEY$(20), but this does not slow down the drawing of the squares -- it just increases the time between squares (see UG page 276, for INKEY$). This is a tediously predictable routine -- it is the same every time. The predictability is shown in Icon 1.1.

Note that Figures are not computer output, they may be diagrams or tables which are there to assist in the understanding of the text. An Icon -- which is 'an image, picture, or representation' according to the dictionary -- is an exact copy of a display on the screen, it is a screen dump onto a printer.
Need a rest? Take Five.

An unsquare dance

I walk forward a certain, fixed, distance and turn through a certain, changing, angle: what happens?
Solution: see PROC_INSPIRALI.
A$ is local again, tedious but safe, and the routine repeats until the F key is pressed. The distance is kept constant (ie SIDE), but the angle (ANG) is incremented (by INC) at each pass through the indefinite loop (ie REPEAT. . .UNTIL. . .). This routine produces a vast array of unpredictable results, which, once known, are completely predictable. It is named PROC_ANSPIRALI because it is an INward SPIRAL, coded Iteratively. Iteration means, as explained in the previous chapter, that the control of the procedure is by a loop mechanism -- in this case REPEAT. . .UNTIL.

An outward SPIRAL is shown by PROC_OUTSPIRAL, in which the angle remains constant and the distance increases, and is what we normally mean by a spiral. Icons 1.2 and 1.3 show two examples of outward spirals for varying values of the fixed angle.

An outward spiral -- as the name spiral suggests -- keeps on spiralling outwards, but an inward spiral does nothing as common as that. Icons 1.4 to 1.7, are examples of four highly different shapes. Try to watch what happens as the plotting unfolds: if it helps to slow down the process, change the value of the parameter in the INKEY$.

The path begins by spiralling inwards, that is, turning in on itself. After a varying number of turns (depending upon INC) the angle becomes greater than 180 degrees, and so the path appears now to unwind. Allowing PROC_INSPIRALI to carry on until completion always results in a closed figure, ie the path ends up where it started, and it retraces the original path. Using PROC_INSPIRALI is a beneficial exercise for the imagination.
As a further way of producing the same (well, almost) effect, examine PROC_INSPIRALR. The final R is for Recursive, and this is a less efficient method for producing the same effect as the iterative version. The routine is recursive because in its own body it calls itself (ie PROC_INSPIRALR(SIDE,ANG + INC,INC)). That it is less efficient can be seen when some of the effects are duplicated -- we are forever running out of room before it has ended. It's a Raggy Waltz.

Both sides now

Between the inward and the outward spirals there is the limbo spiral (if you are not in or out you must be in limbo). The limbo spiral has a rather more familiar designation as the circle. To draw a circle you can use the formula X^2 + Y^2 = R^2, or use the two equations X = R*COS (ANGLE) and Y = R*COS(ANGLE). The best way to draw a circle is to move forward a fixed distance, turn through a fixed angle, and carry on until you are back where you started. Try the Circle Game, use PROC_CIRCLE.
It is a circle it is true, but remember that the resolution on the screen is not perfect: perhaps it is possible to get away with less work? PROC_PERIFIXED takes as a parameter the perimeter of the shape you wish to draw, and as the second parameter the number of sides in the shape.
To draw a regular (ie equilateral) triangle of side 400, therefore, we enter.

PROC_RESTART : PROC_PERIFIXED(400,3)

and a triangle is drawn. To draw a succession of shapes, all with the same perimeter being the parameter. It can be seen that the shape soon approaches that of a circle, given the imperfections of the screen resolution. A circle is a shape of constant curvature -- a limbo spiral.
By examination of the result of PROC_POLYGONS, I think that a polygon of 30 sides is more than adequate (even for large perimeters), and 24 sides is a good approximation (see Icon 1.8). We will develop the circle motif further, next chapter: note that to draw a circle of 30 sides with PROC_PERIFIXED (not an optimal method of drawing a circle) takes about two seconds, depending on size.

The snowflake curve

In Mathematics and the Imagination (Kasner and Newman, 1940), there is a chapter on "Change and changeability", and what we have been discussing is all about change and changeability
There is an appendix to their chapter, on Pathological Curves, ". . .each of whom has an individual history resembling no other", and Kasner and Newman start by discussing a normal and healthy set of curves: the polygons which approach closer and closer to circles, as we found with PROC_POLYGONS.
The first pathological curve they discuss is the Snowflake curve, which starts out life as an equilateral triangle (Icon 1.9). Each side of the triangle is trisected (cut into three equal parts), and on each middle third an equilateral triangle is drawn (a first order snowflake, Icon 1.10). The trisection process is repeated again on each side, to produce a second order snowflake (Icon 1.11). The process then continues as long as desired.

This curve is called 'pathological' because -- as you can see -- the perimeter of the snowflake increases with each trisection (it is an extra third larger), however, -- as is also clear to see -- the area enclosed by the snowflake is not infinite, it approaches a limit (as do the polygons). Ultimately, we have a curve of an "infinite" perimeter enclosing a finite area: this is why the snowflake is pathological.
The snowflakes are very pleasing and satisfying to draw: this is why I draw them. As you may be able to appreciate from my description, the snowflaking process is "Take one snowflake, and then modify it". This is an example of recursion: which is another reason why I chose this subject. To clarify what happens I have split the drawing of the snowflakes into three routines.
Just consider what happens along any side. One goes forward a third of the distance, and turns through 60 degrees; one moves forward the same distance, and turns through -- 120 degrees; the same distance again, and turn through 60 degrees; and then that distance again. If the final stage of the snowflaking has been reached, a straight line (without bumps) is drawn.

There are three procedures: (a) to set the basic shape of the equilateral triangle (PROC_SNOWFLAKE); (b) to decide upon whether a straight line or bump is to be drawn (PROC_DECISION); and (c) to draw a bump, with possibly smaller bumps on the bump (PROC_POINT which makes four calls to PROC_DECISION).
These procedures are recursive in a slightly different manner, no procedure refers immediately to itself. What happens is that PROC_DECISION refers to PROC_POINT which refers to PROC_DECISION (and so it continues, until ODER is zero -- not ORDER because OR is a BB keyword).
There are now three ways we can draw an equilateral triangle: we can use a purpose built routine, we can use PROC_PERIFIXED with the number of sides being three, or we can use PROC_SNOWFLAKE with the order equal to zero. The latter:

PROC_START : PROC_SNOWFLAKE(450,0)

and to draw snowflake of order 1 on top of the triangle

PROC_SNOWFLAKE(150,1)

The rest is up to you. Try to move the snowflake to other positions, other sizes, and with different orientations.
As a last task, design routines to draw the Anti-snowflake Curve (Kasner and Newman, 1940 : page 299, and also my Icon 1.12). The triangles are drawn inward, towards the centre, rather than outward. Hint: the only routine which needs altering is PROC_POINT. No answer is supplied.


Next     Top