0% found this document useful (0 votes)
125 views265 pages

Ian O. Angell, Brian J. Jones (Auth.) - Advanced Graphics With The Sinclair ZX Spectrum-Macmillan Education UK (1983)

This book provides an introduction to computer graphics using the Sinclair ZX Spectrum. It covers topics such as graphics operations on the Spectrum, two-dimensional and three-dimensional coordinate geometry, matrix representations of transformations, orthographic and perspective projections, and hidden line removal algorithms. The book is intended to make computer graphics more accessible by providing programming examples and exercises that can be implemented on the Spectrum without requiring expensive commercial software packages. It assumes a basic knowledge of Cartesian geometry and the BASIC programming language.

Uploaded by

T. Sink
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
125 views265 pages

Ian O. Angell, Brian J. Jones (Auth.) - Advanced Graphics With The Sinclair ZX Spectrum-Macmillan Education UK (1983)

This book provides an introduction to computer graphics using the Sinclair ZX Spectrum. It covers topics such as graphics operations on the Spectrum, two-dimensional and three-dimensional coordinate geometry, matrix representations of transformations, orthographic and perspective projections, and hidden line removal algorithms. The book is intended to make computer graphics more accessible by providing programming examples and exercises that can be implemented on the Spectrum without requiring expensive commercial software packages. It assumes a basic knowledge of Cartesian geometry and the BASIC programming language.

Uploaded by

T. Sink
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 265

Advanced Graphics with the Sinclair ZX Spectrum

Macmillan Computing Books

Advanced Graphics with the BBCMicrocomputer Ian O. Angell and


Brian J . Jones

Advanced Graphics with the Sinclair ZX Spectrum Ian O. Angell and


Brian J . Jones

Assembly Language Programming for the BBC Microcomputer Ian Birnbaum

AdvancedProgramming for the 16K ZX81 Mike Costello

Beginning BASIC Peter Gosling

Continuing BASIC Peter Gosling

Practical BASIC Programming Peter Gosling

Program Your Microcomputer in BASIC Peter Gosling

Codes for Computers andMicroprocessors P. Gosling and Q. Laarhoven

Microprocessors andMicrocomputers - their use and programming


Eric Huggins

MoreReal Applicationsfor the Spectrum and ZX81 Randle Hurley

The Sinclair ZX81 - Programmingfor Real Applications Randle Hurley

Z80 Assembly Language Programming for Students Roger Hutty

Digital Techniques Noel Morris

Microprocessor andMicrocomputer Technology Noel Morris

The Alien, Numbereater, and OtherPrograms for Personal Computers - with


notes on how they werewritten John Race

Understanding Microprocessors B. S. Walker

Assembly Language Assembled - for the SinclairZX81 Tony Woods


Advanced Graphics with the
Sinclair ZX Spectrum

Ian o. Angell and Brian J. Jones


Department ofStatistics and Computer Science,
Royal Holloway College,
University ofLondon,
Egham, Surrey
© Ian O. Angell and Brian J. Jones 1983

All rights reserved. No part of this publication may be reproduced or


transmitted, in any form or by any means, without permission.

First published 1983 by


THEMACMILLAN PRESS LTD
London and Basingstoke
Companies and representatives
throughout the world

ISBN 978-1-349-06765-7 ISBN 978-1-349-06763-3 (eBook)


DOI 10.1007/978-1-349-06973-3

The paperback edition of this book is sold subject to the condition that it
shall not, by way of trade or otherwise, be lent , resold , hired out,or otherwise
circulated without the publisher's prior consent in any form of binding or
cover other than that in which it is published and without a similar condition
including this condition being imposed on the subsequent purchaser.
Contents

Preface ix

Introduction
Aims of the book. Motivation and format. How to approach the contents.
Three levels: example programs, a program package or a textbook. A substantial
example to illustrate what can be drawn after reading the contents of this book.

1 Graphics Operations of the ZX Spectrum 5


The Sinclair Spectrum microcomputer. How the computer makes television
pictures. BASIC commands for drawing with pixels. High-resolution and low-
resolution graphics . Simple character block graphics and animation. Video
games.

2 From Real Coordinates to Pixels 27


Routines for mapping real two-dimensional space into screen pixels . Scaling
factors, moving origin, drawing lines and polygonal areas given in real coordin-
ates. Windows on space . Patterns as a first step in two-dimensional graphics .

3 Two-dimensional Coordinate Geometry 45


Two-dimensional coordinate systems - origin, axes, points, vectors , lines and
curves, and their properties. Clipping . Functional representation and parametric
forms . Polygons and convex areas : inside and outside, orientation.

4 Matrix Representation of Transformations on Two-dimensional Space 62


Explanation of matrices. Translation, rotation and scaling (reflection) trans-
formations. Three-by-three matrix representation of two-dimensional space.
Using matrices to transform points. Inverse transformations. Combining trans-
formations. Positions. Construction and views of two-dimensional scenes.

S Character Graphics on the ZX Spectrum 83


Characters on the Spectrum. Graphics characters . Medium-resolution graphics.
User-defined characters. Alternate character sets. A program for generating and
editing characters. Applications for games, etc. Tessellated patterns.
vi Contents

6 Diagrams and Data Graphs 103


Construction of diagrams. Cursors. Labelling. Drawing axes. Histograms. Pie-
charts and hatching . Discrete and continuous graphs .

7 Three-dimensional Coordinate Geometry 124


Three-dimensional coordinate systems. Vector representation of points, lines
and planes. Properties of these objects - intersection of lines and planes. Repre-
sentation of surfaces. Sides of a surface. Orientation of two-dimensional triangles .

8 Matrix Representation of Transformations on Three-dimensional Space 143


Four-by-four matrix representation of translation, rotation and scaling (reflection)
transformations on three-dimensional space. Inverse transformations. Combining
transformations. Rotation about an arbitrary axis.

9 Orthographic Projections 154


Setup (and storage) of simple objects - vertices, lines and facets. Introduction
to projections. Orthographic projection. Positions (SETUP, ACTUAL and
OBSERVED). Maintaining the vertical. Definition of scenes . Bodies of revolution
(rotation).

10 Simple Hidden Line and Hidden Surface Algorithms 172


Orientation of three-dimensional triangles. Discussion of general problem of
hidden line and surface elimination. A simple algorithm for convex solids - an
implementation where objects are not stored (for example, body of revolution).
A 'front to back' algorithm for special mathematical surfaces .

11 Perspective Projections 182


Theory of perspective. Drawing simple objects in perspective . Extension of
previous algorithms to the perspective case.

12 A General-purpose Hidden Line Algorithm 191


An algorithm to deal with the general case of a perspective view of a stored
three-dimensional scene that has no special properties.

13 Advanced Programming Techniques 203


String displays. Display-me positions . Simple machine-code for graphics . Real
time animation. Utilities for program development. BASIC structure. Optimisa-
tion of BASIC for speed or space. Synchronised patterns.

14 A Worked Example for a Video Game 221


Problems likely to be encountered when constructing a video game.

15 Projects 235
Ideas for extended programs in computer graphics.
Contents vii

Appendix A: Implementing Programs on the 16K Spectrum 239

Appendix B: Basic Program Listings 241

References and Further Reading 244

Index 246

Where to Find Routines referred to in Text 253

Details ofSoftware Cassette 255


Preface

With the rapid advance of computer technology has come a substantial reduction
in the price of computer hardware . In the coming years the price of peripheral
devices will also tumble. This means that users with a limited budget , who
previously had access only to the most elementary computing devices, will soon
be able to afford the most sophisticated computers. They will also be able to
escape from the limitation of tabular numerical output and buy microprocessor
attachments for television monitors or inexpensive special-purpose colour
graphics devices. Sinclair computers have always led the field in this respect.
Software, however, does not appear to be getting cheaper.
Because of the enormous capital expend iture required to set up graphical
output in the past, both in machines and software, the subject of computer
graphics has been the preserve of large research groups. This inaccessibility has
led to a mystique growing up around the subject and it has achieved a false
reputation for difficulty. This book is an attempt to lay the ghost of com-
plexity; it will also show that complicated (and hence expensive) software
packages, which are naturally of great value in research organisations, need not
frighten away the average computer user. For most purposes these packages are
unnecessary. This book, as well as being an introduction to computer graphics,
may be considered a (very inexpensive) software package: it is a lot cheaper
than commercially available packages! Naturally, because of this fundamental
approach, users have to achieve a reasonable understanding of their graphics
device before pictures, other than those provided, may be drawn . This need
not be a disadvantage ; the amount of groundwork required will be seen to be
very limited. As a direct result , the knowledge of the user grows along with the
package and he is far less likely to misinterpret any of the graphical routines.
References are given and relevant further reading material is recommended in
order to expand the reader's horizons in the subject.
It is assumed that the reader has an elementary knowledge of Cartesian
coordinate geometry (the authors recommend the books detailed in Cohn
(1961, Coxeter (1974), and McCrae (1953) - see References), and also of the
BASIC programming language (see the Spectrum BASIC Handbook (Vickers
(1982) and Hurley (1982»). Many interesting programming exercises are proposed,
and these should raise the standard of the reader's BASICexpertise. BASIC is a
universally popular language, available (in various guises) on all types of micro-
computer, so the programs may be easily adjusted to run on machines other
x Preface

than the Spectrum : it is also a good medium for transmitting the algorithms
used in computer graphics, enabling readers to translate these ideas readily
into any other computer language of their choice .
The concepts necessary for the study of computer graphics are organised as
a combination of theory and worked examples ; these are introduced as and
when needed in the natural progression of the subject. Some program listings
form part of the examples and these should not be considered just as algorithms
that describe solutions to fundamental graphical problems, but also as a computer
graphics software package in BASIC, or simply as programs to draw patterns.
Alongside the examples are a series of exercises that expand these ideas. The
practical problems implicit in programming the various concepts of computer
graphics are often more a source of difficulty to the student than the concepts
themselves. Therefore it is essential that readers implement many of the program
listings given in the book in order to understand the algorithms, as well as
attempt a large number of exercises. As an extra learning aid, a companion audio-
cassette tape is being made available; this contains most of the larger program
listings given in this book . If readers are nervous of the mathematics, they should
run the programs first before studying the theory.
This approach to the subject has been used with great success in teaching
computer graphics to undergraduates and postgraduates at Royal Holloway
College. Quickly producing apparently complex pictures results in the positive
feedback of enthusiastic interest. The ability to construct pictures on line-
drawing and colour interactive graphics screens makes a long-lasting impression
on students; and the step-by-step approach brings them very quickly to the
level of very sophisticated computer graphics. That level is outside the scope
of this book, but where necessary readers will find relevant references to guide
them into the more advanced topics.
This book is aimed at those who are competent BASIC programmers but
complete beginners in graphics. It contains the elementary ideas and basic infor-
mation about pixel and two-dimensional graphics, which must be mastered
before attempting the more involved ideas of character and three-dimensional
graphics. This is followed by a section relating to character graphics and the
display of data (in line drawings and colour) - probably the most important
non-specialised, commercial use of computer graphics. Later chapters introduce
the reader to the geometry of three-dimensional space , and to a variety of
projections of this space on to the two-dimensional space of graphics devices.
The related problems of hidden lines and hidden surfaces, as well as the con-
struction of complex three-dimensional objects, are dealt with in detail. Finally,
we return to advanced ideas in BASIC programming and a large worked example
of a video game.
Graphics is one of the most rapidly expanding areas of computer science. It
is being used more and more in the fields of Computer Aided Design (CAD),
Computer Assisted Management (CAM) and Computer Assisted Learning (CAL).
At one time it was only the big corporations such as aircraft and automobile
Preface xi

manufacturers that used these techniques, but now most companies are realising
the potential and financial savingsof these ideas. What is more, not only is
computer graphics profitable, it's fun! The Sinclair Spectrum is an ideal machine
on which to learn the basics of computer graphics, and an excellent springboard
to the most sophisticated (and expensive) graphics devices.
We hope this book will display some of the excitement and enthusiasm for
computer graphics experienced by us, our colleagues and students. To demon-
strate just how useful computer drawings are for illustrating books and pam-
phlets, all the pictures here were drawn by computer specifically for this book.
Introduction

This book may be read at a number of different levels. Firstly, it can be considered
as a recipe book of graphics programs for those who simply want to draw
complex pictures with their Spectrum. We naturally hope that the reader, having
drawn these figures, will be inspired to delve deeper into the book in order to
understand how and why the programs were constructed. Secondly, some of the
programs may be used as a package to produce and label data diagrams (pie-charts,
histograms and graphs) for business and laboratory use. Finally, and the main
reason for writing the book, it is an introductory text to computer graphics,
which leads the reader from the elementary notions of the subject through to
such advanced topics as character graphics, construction of three-dimensional
objects and hidden line (and surface) algorithms.
The complex programs later in the book are much too involved to be given as
a single listing. Furthermore we will see a great deal of repetition in the use of
elementary algorithms. Therefore we use the top down or modular approach in
writing and explaining programs. The solution to each major graphics problem is
conceived as a series of solutions to subproblems. These subproblems may be
further broken down into a set of problems to be solved (modules). These
modules will be programmed in the form of BASIC subroutines. Each is given an
identifier (in lower case characters) and will solve a particular subtask . Then the
totality of submodules combine to solve the required graphics problem. Because
the program listings are used to represent algorithms for the solution of these
subtasks, we decided in general not to use statements like GO SUB 6000. We
prefer instead to assign the subroutine identifier to the address value at the
beginning of the routine (for example, LET scene3 = 6000) and thus we can
write statements like GO SUB scene3. Weuse lower case for subroutine identifiers
(and groupings of routines in the text) only : all other program variables will be
in upper case to avoid confusion.
Spectrum BASIC does not have the facility of passing parameters into routines.
Values of input parameters have to be set in assignment statements outside the
routine , and the names of output parameters must be known if sensible use is to
be made of the routine . This can be rather inconvenient if you are using someone
else's package of routines. It is essential that users know the names of the input
and output parameters ; therefore in our routines we use the REMarks IN: (to
identify the INput parameters) and OUT: (for the OUTput parameters). We
number our programs so that all program statements are on lines ending in 0,
2 Advanced Graphics with the Sinclair ZX Spectrum

and REMarks on lines ending in 1 to 9 (except the naming of routines) . The IN:
and OUT: REMarks follow directly the naming REMark on lines ending in 1 and
2 respectively. Also the cassette tape listings of programs use character codes to
highlight and colour various REMarks (see chapter 13). In cases where we think
that the word REM detracts from readability of a line we use these codes to
make it invisible. Wehave minimised the REMarks on the cassette so that we can
pack the maximum amount of program listing on to the tape. It is a good idea to
expand these listings by adding the complete REMarks, and SAVE them on your
own tapes.
For those who want only to run our programs, we give a list of complete
programs at the end of each chapter together with suitable data values. In fact
it is a good idea for all, including the serious readers, to SAVE the routines on
tape before approaching each chapter. They can then LOAD, MERGE and RUN
the programs as they occur in the text. The cassette tape available to accompany
the text contains all the larger listings in the book, as well as BYTE data for
diagrams and character sets used in later programs (which would otherwise have
to be constructed by readers themselves, a rather time-consuming process). Our
routines were written for the 48K Spectrum: if you have a 16K machine you
should read appendix A and note the changes that need to be made.
As an example of what to expect, we give below the program required to
draw figure I.1 , a line drawing of a body of revolution in which all the hidden
lines have been suppressed. This will work on both types of machine .

Figure 1.1

The program requires the MERG(E)ing of listings 2.1 ('starf), 2.2 (two
functions FN X and FN Y), 2.3 ('setorigin'), 2.4 ('moveto') and 3.3 ('clip' and
'lineto'). This combination of routines will be called 'lib 1" and it was designed
for drawing line figures on the television screen .
To 'lib 1' must be added listings 3.4 ('angle'), 8.1 ('mult3' and 'idR3 '), 8.2
('tran3'), 8.3 ('scale3'), 8.4 ('rot3'), 9.1 ('100k3') and 9.2 ('main program').
Introduction 3

Routines, which when combined we call 'lib3', are used for transforming and
observing objects in three-dimensional space.
We need also listing 10.3 ('revbod ') as well as the 'scene3' routine given in
listing I.l below.

Listing I.l
6000 REM scene3/fLy ing saucer
6010 DIM X(12): DIM Y(12)
6020 DIM S(6): DIM T(6)
6030 DIM A(4,4): DIMB(4,4): DIM R(4,4)
604l1l DATA 0,3,3,2,5,1, 5,0, 4,-1, 0,-3
6050 RESTORE scene3
6060 LET revbod = 6500
6069 REM cr ea t e object.
6070 LET NUMV = 5
6080 INPUT "NUfotlER OF HORIZONTAL LINES",NUMH
6090 INPUT "ANGLE PHI ";PHI
6100 FOR I = 1 TO NUMV + 1: READ SO), TO): NEXT I
6109 REM position the observer.
6110 GO SUB idR3: GO SUB Look3
6129 REM draw object.
6120 GO SUB revbod
6130 RETURN

Figure I.1 requires the data HORIZ = 12, VERT = 8, EX = 1, EY = 2, EZ = 3,


DX = 0 , DY = 0, DZ = 0 , NUMH = 16 and PHI = O. Each value has to be typed in
individually on request by the machine . The picture will take about 5 minutes to
draw , so be patient. Run the program with different data values. What happens if
HORIZ = 6 and VERT = 4 , and the other values stay the same? Set HORIZ = 15,
VERT = 10, EX = 1, EY = - 2, EZ = 3, DX = I,DY =0 and DZ = O. Try
NUMH = 20 , PHI = 0 .1. You will have to read up to and including chapter 10
to understand the details of what is happening .
This example illustrates the reasoning behind the layout of this book. Assum-
ing that you are a fast typist, or that you have bought the accompanying tape,
then a relatively complex three-dimensional picture can be constructed very
quickly with a minimum of fuss. Even one-finger typ ists (like the authors) will
have little difficulty in implementing this and the other programs , before they
go on to study the book in detail.
We hope that this example will inspire you to implement all the programs in
this book, to try most of the examples, and then to go on to draw your very
own computer graphics pictures.
Now you can read the rest of our book and we wish you many happy hours
with your Spectrum.
1 Graphics Operations of the ZX
Spectrum

Throughout the course of this book we will be assuming that the reader is reason-
ably familiar with the BASIC programming language on the ZX Spectrum. In
this chapter, however, we shall be looking at some of the BASIC commands -
those concerned wholly or partly with graphics. With a seriesof example programs
and simple exercises we shall examine and explore the Spectrum's capabilities.
In the chapters that follow we shall use this knowledge to develop a sound
understanding, both practical and mathematical, of computer graphics.
Initially we shall consider the hardware and software facilities available for
producing pictures. All microcomputers that produce television pictures generate
their graphical display using RASTER SCAN technology. This is also true of
most of the newer commercial mini and main-frame computers. An area of memory
is reserved to hold the display information for the screen and this is examined,
bit by bit , as the electron beam sweeps across the raster screen. The display is
composed of points, each of which is represented by a single bit (a binary on/off
switch) in the memory. In the simplest case the beam is switched on for a short
period each time a binary on is found , thus producing a point of light on the
screen .

PAPER and INK

On the Spectrum we are given two commands ; these directly control the way
that the points are displayed. This affects the picture, which is made up of INK
dots (binary ons) on a PAPER background (binary offs). The commands, named
PAPER and INK (naturally), are called by using the name followed by a number
N (0 ~N ~9) .
PAPER N sets the background colour of the picture. After this statement is
executed, all newly generated binary offs in the memory will be displayed in
colour N (that is, until another PAPER command is executed) .
INK N sets the points of light corresponding to binary ons to colour N in a
similar way .
The number N, when in the range 0 to 7, represents the colour printed above
the corresponding numeric key on the keyboard. IfN is 8, then the colour
6 Advanced Graphics with the Sinclair ZX Spectrum

previously set for an area is used. If N is 9, then the colour of PAPER/INK is


set to either black or white and will contrast with the other INK/PAPER colour
currently in use. In general, black INK on white PAPER is clearest , as is obvious
from any book, and this is the normal setting the for Spectrum.

Display File

This type of picture is referred to as a memory-mapped display since it corres-


ponds directly to the contents of an area of memory. On the Spectrum this part
of the memory is known as the display file and starts at location 16384. A simple
exploration of how the display is affected by changing the contents of the
memory can be made with a program such as listing 1.1.

Listing 1.1
10 LET CORNER = 16384
20 l.ET VALUE = 137
30 POKE CORNER,VALUE
40 STOP

This program uses POKE to store a VALUE (entered as a decimal) in the first
location of the display me. This location holds the information for the top left-
hand CORNER of the screen. Since each location, or byte, contains eight binary
bits, the first eight points on the display are affected. These change to show a
pattern equivalent to the binary representation of the VALUE : in this case
10001001.

Exercise 1.1
(i) Experiment with different VALUEs and change the program either to ,
(a) use BIN (binary) representation for VALUE, or to
(b) use a FOR. . .NEXT loop to change VALUE.
(ii) Use the PAPER and INK commands to change the background and fore-
ground colours and then re-run the program to see what difference this makes.

BORDER

When the PAPER colour is changed it soon becomes obvious that we cannot
write on the whole of the screen. A BORDER is left around the edge of the
PAPER to avoid the distortion at the edge of the screen suffered by all television
displays. The colour of this BORDER can be changed, in a similar way to the
PAPER and INK colours , by the command

BORDERN

where N is in the range 0 to 7 and indicates the new BORDER colour.


Graphics Operations of the ZX Spectrum 7

Character Blocks

A complete picture can be built up by storing various VALUEs at locations in


the display memory in a similar way to listing 1.1. For instance, we could store
the eight VALUEs 0, 98 ,148, 136,136, 136, 148,98 in the display-file loca-
tions that represent the start of eight consecutive lines on the screen (see listing
1.2). We see the pattern of INK dots corresponding to the 'ones' shown in
figure 1.1 .

128 64 32 16 8 4 2
00000000 = o
01100010 = 64 + 32 +2 = 98
10010100 = 128 + 16 +4 =148
10001000 = 128 +8 = 136
10001000 = 128 +8 = 136
10001000 = 128 +8 = 136
10010100 = 128 + 16 +4 = 148
01100010 = 64 + 32 +2 = 98

Figure 1.1

This is the way in which characters are defined (and redefined) on the
Spectrum, but we shall leave further investigation of this until chapter 5. Never-
theless it does illustrate that a picture, even as small as this, takes time to prepare
and requires a comparatively complicated program to produce the display.

Listing 1.2
10 LET CORNER = 16384
20 LET LINE = 256
30 DATA 0,98,148,136,136,136,148,98
40 FOR I = 0 TO 7
50 LET MEMORY = CORNER + I*LINE
60 READ VALUE
70 POKE MEMORY,VALUE
80 NEXT I
90 STOP

PLOT and DRAW

We have seen how the screen display can be changed by storing different values
in the display file . But there are over six thousand locations in the display file
and changing each of these individually would be quite tedious. We obviously
need a more effective method of changing the display .
BASIC provides us with graphics commands to deal with this problem, the
simplest of which are PLOT and DRAW. All the graphics commands treat the
display as a grid of 256 points horizontally by 176 points vertically (45056 in
total). These points are known as pixels and are individually identified by a pair
8 AdvancedGraphics with the Sinclair ZX Spectrum

of integers. The graphics commands help in constructing pictures by allowing us


to control a graphics pen, which is initially positioned over pixel (0, 0) . We can
now explain these commands.
PLOT X, Y moves our pen to pixel (X, Y) and plots an INK point there.
DRAWX,Y draws a line from our pen 's current position to the point, X
pixels away horizontally and Y pixels away vertically. If X is negative, the point
will be to the left and if X is positive, it will be to the right. Similarly if Y is
negative, the point will be below our old position, or if Y is positive, above .
After the execution of these commands, the pen remains over the last pixel to
be visited, awaiting the next command . Before examining the other more advanced
graphics commands , we shall first see what is possible using only lines and/or
points.
We are now in a position to draw large-scale pictures on the screen. For
instance , we can draw a box around that area of screen available for graphics
(listing 1.3) .

Listing 1.3
10 PLOT 0,175
20 PLOT 255,175
30 PLOT 255,0
4(J PLOT 0,0
50 IF INKEYS 0'000 THEN GO TO 50
60 IF INKEYS = .... THEil GO TO 60
70 DRAW 0,17 5
80 DRAW 255,0
90 DRAW 0,-175
100 DRAw -255,0
110 STOP

This program first PLOTs points at the corners of the PAPER; it then waits
until a key is pressed before joining them up by DRAWing lines around the
boundary of the PAPER. On comparing the PLOT and DRAW commands we see
that there is an important difference in the way they work: the PLOT command
uses the absolute pixel coordinates, whereas the DRAW command uses the
relative positions of the points. This means that , in order to draw a line segment
between two pixel points on the screen , it is first necessary to use PLOT to
move the graphics pen to the point at one end of a line segment, then work out
the position of the second end point relative to the first, before finally the line
may be DRAWn. Note that in listing 1.3 all the points are decided before the
program is run. In general, points are more likely to be INPUT, READ or
calculated while the program is running .

Exercise 1.2
Write a program that calculates the position oflines to draw a grid. DRAW them
using two FOR. ..NEXT loops (one for horizontal lines , the other for vertical
lines).
Graphics Operations of the ZX Spectrum 9
Exercise 1.3
Write a program that accepts N pairs of pixel coordinates as INPUT from the
keyboard, and then DRAWs an irregular polygon of N sides by joining the points
in order. (This requires some careful thought since the first point must be joined
to the last.)

PRINT and LIST

So far we have not discussed the most obvious method of changing the display,
namely using the PRINT and LIST commands. This is because these commands
use character-size blocks and are designed primarily for use with low-resolution
graphics. This topic will be dealt with in chapter 5 but, since the Spectrum allows
high-resolution and low-resolution graphics to be freely intermixed, we give a
small example here . Suppose we add the line

5 LIST

to the start of the program for exercise 1.2, and then set the program to draw a
grid of 32 vertical lines and 22 horizontal lines. We get a display similar to figure
1.2, which shows the size and position of the character blocks.
. . '

,"' 0,
-tr , Ii' I
.' - :t'3(::)1
='::'l
~::'l
::"
::"
-::'l
" ::" ")1::>, I ='55 lZI

~~~~-t;;l~~.f-+-H-t-H-++~*~~~ -_. -
~
~'"
"

t31211 '

:: __ fi.

k
-
'if - - , .C

"
...
[.;. -- = --

Figure 1.2

We can use the PLOT command to demonstrate the high-resolution capabili-


ties of the Spectrum by drawing fractals (see Mandelbrot, 1977)_
To draw a simple fractal we follow this routine. Imagine a square with sides
of length 4n . This may be divided into 16 smaller squares, each with sides of
10 Advanc ed Graphics with the Sinclair ZX Spectru m

smaller
length 4 n - 1 , which we number I to 16 as in figure 1.3. Four of these
squares, numbers 2, 8, 9 and 15, are rearrang ed to produce figure 1.4.

13 14- 1S 16

9 10 11 12

5 6 7 8

1 2 3 4

Figure 1.3

1.5

1.3 1.4 1.6

1.0 1.1. 1.2 IS

9 5 6 7

1 3 4

Figure 1.4

squares ,
Each of the squares in the pattern is now split up into 16 even smaller
process until
in the same way, and these are similarly rearranged. We repeat this
consists
we have squares with sides of length I. The resulting fractal pattern
in
entirely of unit squares, which we can PLOT as single pixels. The 3program
4 thus in the
listing 1.4 starts from a square with sides of length 64, which is ;
other. The
program there must be three FOR... NEXT loops nested inside each
final picture produced is shown in figure 1.5.
Graphics Operations of the ZX Spectrum 11

Listing 1.4
10 DIM X(16): DIM Y(16)
20 FOR 1 = 1 TO 4
30 FOR J = 1 TO 4
4~ LET K = 4*1 + J - 4
5~ LET X(K) = J - 3: LET Y(K)=I - 3
60 NEXT J: NEXT 1
70 LET X(2) = 0: LET Y(2) =-3
80 LET X(8) = 2: LET Y(8) = 0
90 LET X(9) = -3: LET Y(9) =-1
100 LET X(15) = -1: LET Y(15) = 2
110 FOR 1 = 1 TO 16
120 FO R J = 1 TO 16
130 FOR K = 1 TO 16
1~ LET XX = 16*X(I) + 4*X(J) + X(K)
150 LET YY = 16*Y(I) + 4*Y(J) + Y(K)
160 PLOT 128+XX,88+YY
170 NEXT K: NEXT J: NEXT 1
180 STOP

Figure 1.5

INVERSE and OVER

We shall now consider the options that affect the way in which lines and points
are placed on the screen. There are two commands, and to use them we must
enter the command name followed by a number. The number is I to turn the
effect on, and 0 to turn it off again.
INVERSE: while this effect is on, all lines or points will be draw in the
background (PAPER) colour . That is, the binary switches will be turned off
instead of on .
OVER: while this effect is on , any pixel affected by a graphics command will
be flipped to its opposite state . Any pixel of INK is changed to the PAPER
colour , and vice versa. That is, the binary switch for the pixel is flipped over to
the other position .
Using these commands we can produce programs that generate seemingly
complex patterns and rapidly changing displays. Listing 1.5 gives a program that
combines two methods of creating complicated patterns from very simple
instructions.
12 Advanced Graphics with the Sinclair ZX Spectrum

Listing 1.5
10 OVER 1
20 LET LINES = 40fl
30 =
LET A 0 : LET ANGLE = 2*PI/LINES
40 FOR I = 1 TO LINES
50 =
LET X 85*COS A
60 =
LET Y 85*SIN A
70 PLOT 128,88
80 DRAW X, Y
90 LET A = A + ANGLE
100 NEXT I
110 OVER 0
120 STOP

On a display composed of discrete points (pixels), angled lines will be drawn


as a series of short, horizontal or vertical steps . When two such lines are drawn
close together at slightly different angles, many of the steps on the lines will
overlap. Consider figure 1.6, drawn by listing 1.5. The lines that form the central
area overlap each other many times and so this area would be a mass of black
were OVER not used. With OVER on, those pixels that lie on an odd number of
lines are switched on, whereas the others remain off. This produces the striking
pattern at the centre of the figure. On the other hand the outer area of the
pattern is produced by holes, left by the line steps , of pixels not lying on any
line.

Figure 1.6

Exercise 1.4
Alter listing 1.5 to INPUT the value of LINES and also to INPUT a string variable,
indicating whether or not the OVER option is to be used . Use this program to
explore the parts played by OVER and by the steps on adjacent lines as LINES
is varied.
Graphics Operations of the ZX Spectrum 13

The repeated use of random numbers to produce a variety of rapidly changing


graphical displays has been a favourite device for attracting attention to com-
puters. Listing 1.6 shows one simple illustration of this method using RND and
OVER to place pixels at random about the screen.

Listing 1.6
10 OVER 1
20 LET X = !~T (RND*256 )
30 LET Y = HIT (RND*176)
~ PLOT X, Y
50 BEEP 0.0S,(X - Y)/10
60 GO TO 20

Exercise 1.5
Alter listing 1.6 to DRAW lines, either between the random points as they are
generated, or from the centre of the screen (128, 88) to each point.

In the above exercise we saw that the OVER option ensured that the display
changed with each command, even if the same command was repeated, for
example , by DRAWing the same point, or line. The OVER option may be used
in th is way to display an object briefly - by drawing it twice, once to put it on
the screen and again to take it off. Listing 1.7 moves a point around the screen
by PLOTting it at its new position and immediately PLOTting its last position
again to remove the old point.

Listing 1. 7

10 OVER 1 : PAPER 0: INK 7: BORDEP. 4: CL S


20 LET SPEED = 2
30 ~ET X = 0: LET Y = 0
40 LET XAD D = SPEED: LET YADD = SPEED
50 PLOT X, Y
60 LET OLDX = X: LET OLD Y = Y
70 LET X = X + XA~D
80 IF X > 255 - SPEED OR X < SPEED THEN LET XADD = -XADD
90 LET Y = Y + '(ADD
10PJ IF Y > 174 - SPEED OR Y < SPEED THEN LET YADD = -YADD
11 ~ FLOT X,Y
120 PLOT OLDX,OLDv
130 GO TO 60

We can extend this program to allow keyboard control of the moving point
(listing 1.8). The lower case letters about " f" enable the point to move in eight
separate directions under our control. If a "p " is typed then the point leaves a
trailing line that shows its past movements : if a " q" is typed then the point
ceases to leave a trail.
14 Advanced Graphics with the Sinclair ZX Spectrnm

This type of animation is an important and commonly used technique. We


shall use it extensively, both in programs like the game in chapter 14, and in
programs like the 'cursor' routine in chapter 6 .

Listing 1.8

10 OVER 1
20 LET X = 0: LET Y = 0
30 PLOT X,Y
40 LET OLDX =X: LET OLDY =Y
50 LET XADD =0: LET YADD =0
60 LET AS =INKEYS: I F AS = .... THEN GO TO 60
n: IF AS = "p " THEN OVER 0
80 IF AS ="q" THEN OVER 1
90 I F (AS ="e" OR AS =
"d" OR AS =
"c") AND X > 0 THEN LET XADD = -1
100 IF (AS ="c" OR AS "v" = OR AS =
"b") AND Y > 0 THEN LET YADD = -1
110 IF (AS =" t " OR AS =
"9" OR AS =
"b") AND X < 255 THEN LET XADD =1
120 IF (AS ="e " OR AS "r"= OR AS =
"t") AND Y < 175 THEN LET YADD = 1
130 IF XADD =0 AND YADD 0 = THEN GO TO 60
140 LET X =X + XADD: LET Y = Y + YADD
150 PLOT X, Y
160 PLOT OLDX,OLDY
170 GO TO 40

We can achieve large-scale animation by using lines to extend or contract a


polygonal area. Listing 1.9 uses this method together with the INVERSE com-
mand to form a fast zoom effect.

Listing 1.9
10 LET I =0: INK 9
20 LET UP = 175: LET ACROSS 255 =
30 LET X = 0: LET Y =
0
40 L ET DIF = 1
50 INVERSE I
60 PLOT X, Y
70 DRAW 0,UP: DRAW ACROSS,0
80 PLOT X, Y
90 DRAW ACROSS,0: DRAW 0,UP
100 LET X = X + DIF: LET Y =
Y + DIF
110 LET UP = UP - 2 * DIF
120 LET ACROSS = ACROSS - 2 * DIF
130 IF UP < 0 OR UP =175 THEN LET DIF = -DIF: LET I = 1 - I
140 IF UP = 175 THEN PAPER RND*7: CLS
150 GO TO 50

Exercise 1.6
Draw a solid square composed of 40 by 40 pixels. Move this area about the
screen under keyboard control. Note that you need change only the edges of the
square.
Graphics Operations of the ZX Spectrum 15

FLASH and BRIGHT

Having seen what is possible in black and white, we shall now turn our attention
to colour. The Spectrum can have all the colours on the screen at once, but
inside each character block there can be only two colours, PAPER and INK.
These colours may be BRIGHT and/or FLASHing; also, special effects like
OVER and INVERSE can be turned on or off in the same way.
FLASH: when FLASH is set for a given block, the colours within that block
will alternate between INK on PAPER and PAPER on INK.
BRIGHT: blocks with BRIGHT set will show both PAPER and INK at
increased BRIGHTness. This has the effect of making non-BRIGHT blocks look
darker.
FLASH and BRIGHT can also be set to 8, so that the pre-existing setting for
a block is unchanged by PRINT.

Attributes

The current combinations of FLASH, BRIGHT, PAPER and INK colours for
each character block are stored in memory in the attribute file . This contains
one location for each of the character blocks; it is located in memory immediately
after the display file, and starts at location 22528. We can use listing 1.10, a
modified version of listing 1.1, to alter these values directly, as we did with the
display file.
Listing 1.10
10 LET CORNER = 22528
20 INPUT "VALUE = BIN "; LINE VS
30 LET VALUE = VAL ("BIN " + VS>
4lil PRINT AT 0,0;"*"
50 POKE CORNER,VALUE
60 GO TO 20

Exercise 1.7
Use the program from listing 1.10 to alter individual bits within the VALUE
stored in the first location of the attribute file.

This VALUE affects the whole of the first character block by indicating for
points in that block whether FLASH and BRIGHT are on or off, and what
PAPER and INK colours are used. These pieces of information make up a
BINary number in the following manner

FLASH - a or 1; BRIGHT - a or 1; PAPER - 000 to 111; INK - 000 to 111

Thus we can calculate the meaning of a value in the attribute me in the way
shown in figure 1.7.
16 Advanced Graphics with the Sinclair ZX Spectrum

FLASH BRIGHT PAPER INK


Normal settings 1 0 5 2
BINary equivalent = 1 0 101 010
BIN 10101010 = 128+32+ 8 + 2 = 170

Figure 1. 7

The above example is the attribute for FLASHing , non-BRIGHT, cyan


PAPER and red INK. The attribute value for any character block can be found
using the function ATTR (ROW, COLUMN). The ROWand COLUMN para-
meters specify the position of the block by counting the number of ROWs
down from the top line and the number of COLUMNs across from the left edge.
These are the same parameters we use to PRINT AT a character block. So it is
easy to write a program that changes the attributes of blocks at random (see
listing 1.11). This has the same effect as randomly POK(E)ing values into the
attribute file (see page 117 of the Spectrum BASIC Handbook (Vickers, 1982)).

Listing 1.11
10 FLASH INT (RND*2)
20 BR IG HT INT (RND*2)
30 PAPER INT (RND*8)
40 INK INT (RND*8)
50 LET ROW = INT (RND*22): LET COL = INT (RND*32)
611' PR INT AT ROW, COL; "*"
70 BEEP 0.1l'2,RND*40
811' GO TO 10

Exercise 1.8
Modify the above program so that it changes just one character block to a
random attribute setting, and then calculates and displays the FLASH, BRIGHT,
PAPER and INK settings from the ATTR function .

For convenience we can use table 1.1 to convert between attribute file value
and the attribute settings.
Table 1.1 Attribute Conversion

PAPER INK MODE

Black Blue Red Magneta Green Yellow Cyan White

Black 0 1 2 3 4 5 6 7 NORMAL
64 65 66 67 68 69 70 71 BRIGHT
128 129 130 131 132 133 134 135 FLASH
192 193 194 195 196 197 198 199 BRIGHT
+ FLASH
Graphics Operations of the ZX Spectrum 17

Blue 8 9 10 11 12 13 14 15 NORMAL
72 73 74 75 76 77 78 79 BRIGHT
136 137 138 139 140 141 142 143 FLASH
200 201 202 203 204 205 206 207 BRIGHT
+ FLASH

Red 16 17 18 19 20 21 22 23 NORMAL
80 81 82 83 84 85 86 87 BRIGHT
144 145 146 147 148 149 150 151 FLASH
208 209 210 211 212 213 214 215 BRIGHT
+ FLASH

Magenta 24 25 26 27 28 29 30 31 NORMAL
88 89 90 91 92 93 94 95 BRIGHT
152 153 154 155 156 157 158 159 FLASH
216 217 218 219 220 221 222 223 BRIGHT
+ FLASH

Green 32 33 34 35 36 37 38 39 NORMAL
96 97 98 99 100 101 102 103 BRIGHT
160 161 162 163 164 165 166 167 FLASH
224 225 226 227 228 229 230 231 BRIGHT
+ FLASH

Cyan 40 41 42 43 44 45 46 47 NORMAL
104 105 106 107 108 109 110 111 BRIGHT
168 169 170 171 172 173 174 175 FLASH
232 233 234 235 236 237 238 239 BRIGHT
+ FLASH

Yellow 49 49 50 51 52 53 54 55 NORMAL
112 113 114 115 116 117 118 119 BRIGHT
176 177 178 179 180 181 182 183 FLASH
240 241 242 243 244 245 246 247 BRIGHT
+ FLASH

White 56 57 58 59 60 61 62 63 NORMAL
120 121 122 123 124 125 126 127 BRIGHT
184 185 186 187 188 189 190 191 FLASH
248 249 250 251 252 253 254 255 BRIGHT
+ FLASH
18 Advanced Graphics with the Sinclair ZX Spectrum

We can think of each pixel on a colour television screen as three dots of light
packed closely together at the vertices of an equilateral triangle . For each pixel
there is one red, one blue and one green dot, and the attribute-file locations are
used to control the illumination of the three different colours. The display file
will indicate that a given pixel is to be plotted in a particular INK colour. The
lowest three bits (bits 0 to 2) of the attribute value for the block containing that
pixel are used to decide whether the green, red and blue dots of that pixel are
on or off. Our eyes contain only three types of colour sensor (green, red and
blue) . Our brain takes the signals from the three dots and combines them into a
single dot of composite colour. So if the last three bits of the attribute are 111,
equivalent to colour 7, we get green, plus red, plus blue. This corresponds to
white light or white INK . The other colour codes, when written in binary form,
can be translated in this way (see figure 1.8).

Colour Number Binary Illuminated Dots

Black 0 000
Blue 1 001 Blue
Red 2 010 Red
Magenta 3 011 Red + Blue
Green 4 100 Green
Cyan 5 101 Green + Blue
Yellow 6 110 Green + Red
White 7 111 Green + Red + Blue

Figure 1.8

When a PAPER-coloured pixel is to be illuminated, the three bits of the


attribute corresponding to the PAPER colour (bits 3 to 5) are decoded in
exactly the same way . Bit 6 in the attribute indicates whether BRIGHT is on or
not, and is used to control the brightness at which all the dots will be illuminated.
When an attribute has the FLASH bit set (bit 7) , the colours corresponding to
INK and PAPER will be alternated. The speed of alternation (that is, the FLASH-
ing) depends on an internal value in the computer : on the Spectrum it changes
about every one-third of a second.
In general, we may safely use two colours for high-resolution graphics, but
beware! No more than two colours may occur in one character block at anyone
time. Subject to this proviso , full-colour high-resolution graphics may be achieved .

Exercise 1.9
Experiment with different colours using the programs in this chapter. Certain
colour combinations can be just too much for a normal television set to cope
with. Unless you are using an expensive monitor instead of a television screen, a
combination of clashing colours for the program in listing 1.5 should produce a
rather interesting effect of waves washing across the screen.
Graphics Operations of the ZX Spectrum 19

Simple Animation

We can produce more animated effects in low resolution by using colours and
FLASH . Listing 1.12 shows some interesting techniques of colour animation.
The first part of the program is particularly useful because the display needs no
maintenance once set up . The boundary of the picture is a sequence of blocks
composed of alternative blocks of FLASHing red PAPER and cyan INK, and
FLASHing cyan PAPER and red INK. On seeing this our brains are tricked into
believing that the red and cyan colours are moving around the boundary
sequence .

Listing 1.12

10 FLASH 1: PAPER 2: INK 5


20 FOR I = 0 TO 1
30 FOR J = 0 TO 15
40 PRINT AT 0,2*J + I;" "
50 PRINT AT 21,2*J + 1 - I; " "
60 NEXT J
70 FOR J = 0 TO 10
80 PRINT AT 2*J + 1,0;" "
90 PRINT AT 2*J + 1 - 1,31;" "
100 NEXT J
110 PAPER 5: INK 2
120 NEXT I
130 FLASH 0: LET P = 0
140 FOR I = 1 TO 20
150 PRINT AT 1,1; PAPER P;"
160 LET P = P + 1: IF P = 7 THEN LET P =0
170 NEXT I
180 GO TO 140

Exercise 1.10
Write low-resolution colour versions of the bouncing point program and the
other animation programs. In your programs move character blocks instead of
pixels around the screen .

CIRCLE and DRAW

The Spectrum has two further built-in high-resolution graphics commands that
we have not yet examined: the CIRCLE command and the DRAWcommand for
curved lines.
CIRCLE X, Y, R draws a CIRCLE of radium R pixels centred on pixel (X,
Y) . It is important to remember that after obeying this command our graphics
pen is left at a pixel on the right-hand side of the CIRCLE, just below the centre .
20 Advanced Graphics with the Sinclair ZX Spectrum

DRAW X, Y, A DRAWs a curved line from the current position to the


relative position X, Y, while turning through an angle A. This curved line will be
an arc of a CIRCLE. The angle through which the line turns is specified in radians
and may be between -PI and PI.
Listing 1.13 demonstrates the use of these commands by producing the
display shown in figure 1.9.

Figure 1.9

Figure 1.10
Graphics Operations of the ZX Spectrum 21

Listing 1.13
10 CIRCLE 128,88,80: LET h = 12
20 LET A ~ 0: LET ADIF = 2*PI/N
30 FOR I = 1 TO N
40 PLOT 128,88
50 LET X = 40*COS A : LET Y = 40*SIN A
60 ORAI' X, Y, - P! : DRA'" X,Y,PI
70 LET A =A + AOIF
80 NE XT I

Exercise 1.11
Figure 1.10 shows the traditional Celtic pattern known as a triskele. Write a
program to draw this type of pattern .

Colours within a Character Block

The use of different INK colours for high-resolution graphics can cause problems
and produce results that are calculable but usually unforeseen. Run the program
in listing 1.14 . It will show just how easily things can go wrong when more than
two colours are used without careful planning.

Listing 1.14
10 PAPER 5: H:K 7 : CLS
20 FOR ! = 0 TO 17 5 STEP 8
30 FLOT ~,I : OR AIi 255,0
40 NE XT I
50 INK ~
60 CIRCLE 128,88,80
70 STOP

This problem can be used to our advantage. We can produce rapidly changing,
and complicated, low-resolution colour displays. Initially we PRINT solid INK
blocks at specified positions on the screen. Any line drawn subsequently will
change the colour of the low-resolution blocks through which it passes. The
impressive speed of this technique can be seen by running the program given in
listing 1.15 .

Listing 1.15
10 INK 7: CLS
20 FOR! = 1 TO 704: FRINT "I " ; : NEXT I
30 LET Dr ST = 80: LET I = 0 : LET D = e
40 INK I
50 FLOT 120,86 + OIST: ORA'" OIST,-DIST: DRAII - CI ST, - DI ST
60 FLOT 127,86 - DIST: DRAII -CIST,DIST: DRAW DrST,DIST
70 LET DIST = DIST - D: IF DIST = 0 OR DIST = 80 THEN LET D = - D
80 LET I = 1+ 1: IF I = 8 THEN LET I = 0
90 GO TO 40
22 Advanced Graphics with the Sinclair ZX Spectrum

A Simple Game

We now include a small game program (listing 1.16) as a final example of the use
of the techniques discussed in this chapter. A worm can move in character block
steps about the screen, horizontally or vertically , under control of the keyboard .
The aim of the game is for the worm to eat the money (or target). The worm gets
longer whenever it eats the target. If at any time the head of the worm runs
headlong into the boundary , or into its own body, then the worm dies. After ten
successful meals the worm returns to its original size, with a fanfare . The game
then continues.
This game was developed using modular , structured methods preferred by
programmers. These methods help to produce quickly a working and understand-
able program. Put simply, we must approach the program as a series of small
tasks that build up block by block into the completed program . For this game
these tasks were tentatively defined as

A. Initialise variables
B. Set up board
C. Control game
D. Update and print score

From this overview of the problems we can set about solving each problem or , if
necessary, split them into yet smaller, more manageable problems. For example ,
task C above could be split into

I. Generate target
2. Use keyboard to change direction of worm
3. Move worm

Task 3 could be further split

a. Draw worm
b. Worm hits boundary or itself, and dies
c. Worm eats money and grows
d. Fanfare

No specific order is implied in this breakdown; for example, you may find that
you want to regenerate the target from inside the fanfare section of program.
These headings are simply a list of tasks that reflect the problems that come to
mind when attempting the solution of a larger problem.
Examine the game below and try to identify which tasks are carried out,
where, in what order, and which have been further subdivided. (Throughout this
book the variable names in lower case will refer to line numbers at the start of
subroutines. This helps to make the program more readable, gives a clear picture
of the algorithm, and hence is good general practice.)
Graphics Operations of the ZX Spectrum 23

Note the use of logical expressions (for example, IF DEAD THEN. ..): see
chapter 13 of the Spectrum BASIC Handbook (Vickers, 1982). Also note the
use of ATTR and SCREEN$ to detect collisions, both by the colour of character
blocks and by their contents. Figure 1.11 shows a typical state of the game.

SCORE 29 HI-SCORE 785

EVEL 3 ,",ORHS 3

Figure 1.11

Listing 1.16

10~~ DIM R(55): DIM C(55)


10~9 REM initialise routine pointers and set hiscore to 0.
1010 LET fanfare = 2000: LET worm = 300~: LET key = 40~0
: LET gobble = 5000: LET status = 6000: LET target = 7000
1020 BORDER 1: PAPER 7: INK 0
1030 LET HSC = 0
1039 REM start/restart for game.
1040 LET SCORE = 0: LET WORMS = 3: LET LEVEL = 1
1048 REM start a new worm, five segments long from row R column C.
1049 REM P is pointer to segment which is to be moved.
1050 LET S = 5: LET P = 1: LET R = 0: LET C = INT (RND*32)
1059 REM set movement variables so that worm is going down.
1060 LET RMOVE = 1: LET CMOVE = 0: LET H$ = "v"
1069 REM clear array of segment positions.
1070 FOR 1=1 TO 55: LET R(I) = -1: NEXT I
1079 REM set truth flags for game (0 = false, not 0 = true).
1080 LET WON = 0: LET DEAD = 0
1089 REM set up screen with yellow strips on top and bottom.
1090 CLS: PRINT AT 0,0; PAPER 6;,,: PRINT AT 21,0; PAPER 6;"
1099 REM print out scores and place a £ note target on the screen.
1100 GO SUB status: GO SUB target
1109 REM main loop of game: check for controls,move worm.
24 Advanced Graphics with the Sinclair ZX Spectrum

1110 GO SUB key: GO SUB worm


1119 REM if nothing has happened keep on Looping.
1120 IF NOT DEAD AND NOT WON THEN GO TO 1110
1129 REM if one worm has eaten £10 give fanfare and start a new worm.
1130 IF WON THEN LET LEVEL = LEVEL + 1: GO SUB fanfare: GO TO 1050
1139 REM make crashing noise.
1140 IF DEAD THEN FOR I = 1 TO 10: BEEP 0.0~5,15: NEXT I
1149 REM if you have another worm left start a new worm.
1150 IF DEAD THEN LET WORMS = WORMS - 1: IF WORMS <> ~ THEN GO TO 1050
1159 REM remove aLL segments by moving pointer aLong from back of worm.
1160 FOR I = 1 TO S: BEEP 0.01,0: PRINT AT R(P),C(P); PAPER 7;" "
1170 LET P = P + 1: IF P > S THEN LET P = 1
1180 NEXT I
1189 RE~ remove target from screen and update score Lines.
1190 PR INT AT Y,X; PAPER 7;" ": GO SUB status
1199 REM use fLashing input to wait for entry before restarting game.
1200 LET IS = CHRS 18 + CHRS 1 + "PRESS ENTER TO START GAME"
+ CHRS 18 + CHRS 0
1210 INPUT (IS + " "); LINE AS
1220 GO TO 1 ~40
20~0 REM fanfare
2009 REM this is pLayed when you go up a Level.
2010 DATA 0.06,18,0.06,19,0.06,21,0.15,27,0.06,21,0.2,27
2019 REM read and pLay the six notes/duration combinations.
2020 RESTORE fanfare: FOR 1=1 TO 6: READ L,T: BEEP L,T: NEXT
2030 RETURN

3000 REM worm


3008 REM worm moves by ta king Last segment a nd moving i t to the front.
3009 REM i f it's not a growt h segment then erase i t at it's oLd pos it ion.
3010 IF R(P) <> -1 THEN PRINT AT R(P),C(P); PAPER 7; " "
3019 REM caLcuLate new position of worms head.
3020 =
LET R = R + RMOVE: LET C C + CMOVF.
3029 REM che ck for coLL ision with boundar ies.
3030 IF R > 20 OR R < 1 OR C > 31 OR C <0 THEN LET DEAD = 1 : RETURN
3039 REM check for coLLis ion with another segment of worm.
3040 IF ATTR (R,C) = 16 THEN LET DEAD = 1: RETURN
3049 REM set row and coLumn of segment to new posit ion.
3050 LET R(P) = R: LET C(P) = C
3059 REM check whether target ha s been eaten.
3060 IF SCREENS (R,C) = "£" THEN GO SUB gobbLe
3069 REM put new segment on screen and move pointer aLong worms bac k.
3070 PRINT AT R(P),C(P); PAPER 2;HS
3080 LET P = P + 1: IF P > S THEN LET P = 1
3090 RETURN

4000 REM key


4009 REM che ck for contr oLs being used.
4010 LET AS = INKEYS: IF AS = "" THEN RETURN
4019 REM make sure aLL Letters are treated as Lower case.
4020 IF CODE AS < 96 THEN LET AS = CHRS (CODE AS + 32)
4028 REM worm can onLy tur n Left or right from course not back on i t se Lf .
4029 REM controL fo r up is pressed, i f you ' re not going down then turn up.
403~ IF AS = "i" AND CMOVE THEN LET RMOVE = -1: LET CMOVE = 0
: LET HS = "t ": RETURN
4039 REM tur n down ( if worm is not going up ).
4040 IF AS = "m" AND CMOVE THEN LET RMOVE = 1 : LET CMOVE 0
: LET HS = "v ": RETURN
4049 REM tu rn Left ( i f worm is not going right ).
4050 IF AS = "i " AND RMOVE THEN LET RMOVE = 0: LET CMOVE -1
: LET HS = "<": RETURN
4059 REM tur n right ( i f worm is not goi ng Left ).
Graphics Operations of the ZX Spectrum 25

4060 IF A$ =
"k" AND RMOVE THEN LET RMOVE =0 : L ET CMOV E =1
: L ET H$ =
" >": RETURN
41H0 RETURN

50fJfJ REM gobbLe


50fJ9 REM eat ta rget, make gobbL ing noises.
5010 FOR I = 2 TO 4 STEP 0.5
5020 BEEP 0.01,EXP I - 1 0: NEXT I
5029 REM add to your sc ore and update scor e- Li nes.
5030 LET SCORE = SCORE + 1: GO SUB stat us
5038 REM make f ive more se gments avai LabL e f or gr owth.
5039 REM i f worm has 55 segments the n it has eaten £10 so you win a ro und.
5040 LET S = S + 5: IF S =55 THEN LET WON = 1: RETURN
5049 REM pLace a new target on the screen.
5050 GO SUB target
5060 RETURN

60fJfJ REM status


6fJfJ9 REM i f your score beats hiscore the n update hi score.
6010 IF SCORE> HSC THEN LET HSC = SCORE
6019 REM pri nt out both s cor e- Line s .
6020 PRINT AT 0,0; PAPER 6;" SCORE ";SCORE, " HI-SCORE ";H SC
6030 PRINT AT 21,0; PAPER 6; " LEVEL " ; L EVEL , " WOR~'S ";WORMS
6040 RETURN

7fJfJfJ REM ta rget


7009 REM choose a char ac t e r bL ock i n the pLayi ng area at random.
7010 L ET X = RND* 31: LET Y =RND*19 + ,
7019 REM che ck t hat it ' s not t he same pLace a s the Last one.
7020 IF X = C AND Y = R THEN GO TO ta rge t
7029 REM check t hat i t ' s not under t he worm.
7030 IF ATTR (Y,X) = 16 THEN GO TO ta rget
7039 REM pri nt new £ note on th e scr een,
7040 PRINT AT Y,X; PAPER 4; "£ "
7050 RETURN

Exercise 1.12
As a final mini-proje ct for this chapter , write a squash game or ping-pong video
game (o r both! ) using low-resolution colour graphics. The ball can be a pixel or
character block , and the bat (s) should be controlled from the keyboard like the
worm in the above program . You will find it useful to tum some of the program
sections from this chapter into subroutines.

In this chapter we have restricted ourselves to using the screen as a fixed piece
of PAPER for patterns and games. To step up from pixel graphics to drawing
pictures of real objects , we need commands that will relate the real world to our
PAPER. In the following chapters we shall explore and develop the techniques
needed to draw these real graphics pictures .

Complete Programs

I. Listing 1.1: no data required.


II. Listing 1.2 : no data required.
26 Advanced Graphics with the Sinclair ZX Spectrum

III. Listing 1.3: no data required.


IV. Listing 1.4: no data required.
V. Listing 1.5: no data required.
VI. Listing 1.6: no data required.
VII. Listing 1.7: no data required.
VIII. Listing 1.8: press keys around character "F" to move point in one of
eight directions, press "P" to start leaving a trail and "Q" to stop trail.
IX. Listing 1.9: no data required.
X. Listing 1.10: no data required.
XI. Listing 1.11: no data required.
XII. Listing 1.12: no data required.
XIII. Listing 1.13: no data required.
XIV. Listing 1.14: no data required.
XV. Listing 1.15: no data required.
XVI. Listing 1.16 (main program and routines 'fanfare', 'worm', 'key', 'gobble ',
'status' and 'target'): use keys "I", "J", "K" and "M" to control move-
ment of worm.
2 From Real Coordinates to Pixels

We have seen that Spectrum imagines its graphics frame to be a rectangular


matrix of addressable points or pixels. These pixels are stacked in NXPIX
(= 256) vertical columns and NYPIX (= 176) horizontal rows. Individuals from
the set of NXPIX by NYPIX pixels can be uniquely identified by a bracketed
pair of integers; these are sometimes called a pixel vector (I, J), where 0 .;;;; I .;;;;
NXPIX - 1 and 0 < J < NYPIX - 1, the vector specifying the position of the
pixel in the Ith column and Jth row : the vector (0, 0) identifies the bottom left-
hand corner pixel of the frame . The Spectrum has its own set of BASIC instruc-
tions that enable users to operate on the matrix of pixels, treating them as
points of light that can be switched off or on. This enables the operator to
approximate lines , or polygons and other special types of area, with a series of
coloured dots (the pixels) .
The chapters that follow can be considered as taking the reader some way
towards generating a two-dimensional and three-dimensional graphics package
for the Sinclair Spectrum: the programs are given in BASIC and rely (with a few
exceptions) on a small number of primitive routines given in this chapter.

Primitives that Map Continuous Space on to the Graphics Frame

In general, computer graphics deals with points, lines, areas and volumes in con-
tinuous two-dimensional and three-dimensional Euclidean space. Pixel graphics
is very limited . The definition of objects that use only discrete pairs of integers
is very rare in most practical applications. We therefore need to consider ways of
plotting views of objects on a graphics screen, where positions are measured in
real units : inches, miles or even light-years! Therefore we consider the relation-
ship between two-dimensional real space and screen pixels. Before we can
attempt this step, however, we must first discuss ways of representing two-
dimensional space using Cartesian coordinate geometry.
We can imagine two-dimensional space as the plane of this page extending to
infinity in all directions. Our description of the coordinate geometry starts by
arbitrarily choosing a fixed point in this space, which we call the coordinate
origin. Through the origin we draw a line that stretches to infinity in both
directions; this is the x-axis . The normal convention is to place this line left to
right on the page (the horizontal). Another two-way infinite line, the y-axis, is
28 Advanced Graphics with the Sinclair ZX Spectrum

drawn through the origin perpendicular to the x-axis ; conventionally this is


placed from the top to the bottom of the page (the vertical) . We now draw a
scale along each axis: unit distances need not be the same on both axes, but this
is normally the case (see figure 2.1). We assume that values on the x-axis are
positive to the right of the origin and negative to the left : values on the y-axis
are positive above the origin and negative below.

+p == (X, Y)

~
+x
- 3 1 2 3

Figure 2.1

Taking any point p in space we can now uniquely fix its position by specify-
ing its coordinates (figure 2.1) . The x-eoordinate, X say, is that distance along the
x-axis (positive to the right of the axis and negative to the left) at which a line
perpendicular to the x -axis passing through p cuts the x-axis, The y-coordinate,
Y say, is correspondingly defined using the y -axis. These two values, called a co-
ordinate pair or two -dimensional vector, are normally written in brackets thus :
(X, V). Note that the x-coordinate comes before the y-coordinate. We shall
usually refer to the pair as a vector - the dimension (in this case two) will be
understood from the context in which we use the term . A vector, as well as
defining a point (X, Y) in two-dimensional space, can also be used to specify a
direction, namely the direction that is parallel to the line joining the origin to
the point (X, Y) - but more of this (and other objects such as lines, curves and
polygonal areas) in chapter 3.
We are now in a position to devise means (the above-mentioned primitive
routines) for mapping such geometrical concepts on to the two-dimensional dis-
crete rectangular matrix of pixels that form the graphics frame .
From Real Coordinates to Pixels 29

Here we concentrate on two-dimensional space: an extension into three-


dimensional space is dealt with starting at chapter 7. In both cases we require a
method of mapping a rectangular area of two-dimensional Cartesian space on to
the graphics frame . For simplicity we start by insisting that this area has its edges
parallel to the x-axis andy-axis of Cartesian space. Initially , we assume that this
rectangular area of space has its bottom left-hand comer identified with the co-
ordinate origin (0 .0, 0.0), while the length of the horizontal edge is HORIZ and
the vertical edge VERT . We first identify the origin with the (0, 0) pixel of the
frame , and then scale the rectangular area so that it fits into the frame; naturally
the area only exactly fits the frame if the ratios HORIZ:VERT and NXPIX:
NYPIX are equal (that is, 256 :176) . This is rarely the case, so we choose a scaling
factor , XYSCALE, that maps the point (HORIZ, VERT) on to a pixel either on
the upper or the right-hand edge of the frame . We can consider this rectangle as a
window on to Cartesian space; no longer anchored to the coordinate origin, it
may wander about space viewing rectangular areas of the same size as the original,
but still having edges parallel to the original coordinate axes. As a general rule we
make HORIZ roughly one-and -a-half times VERT.
At any time during the execution of the program we can move the coordinate
origin from its original position at the bottom left -hand corner of the frame. Its
position relative to the first origin will be stored as XORIG and YORIG, the x-
component andy-component respectively . Initially, (XORIG, YORIG) is identi-
fied with (0.0, 0 .0). Hence any point in Cartesian space with coordinates (XPT,
YPT), a pair of reals, maps into a pixel with horizontal component INT((XORIG
+ XPT)*XYSCALE + 0.5) and vertical component INT((YORIG + YPT)*
XYSCALE + 0.5). (INT is the BASIC function that truncates the fractional part
of a decimal number and returns an integer .) These two components are stored
as funct ions FN X and FN Y (see listing 2.2) . During the construction of a picture
we must consider a plot pen, in value a pair of integers, which moves about the
graphics frame ; initially it is placed at (0 , 0), and in general it is the (XPEN,
YPEN) pixel. The constants NXPIX and NYPIX, and the variables XYSCALE,
XPEN, YPEN, XORIG and YORIG, must be available at all times to the plotting
routines that follow , so these names must not be used for any other purpose. The
routines were written specifically for the Spectrum , but we discuss also the
general principles of constructing similar routines for other graphical devices.
To start with we would have to change the values of NXPIX and NYPIX before
we could use a different machine.
Our first routine 'start' initialises the required variables and prepares the screen
for plotting. Listing 2.1 is an example 'start' routine for the Spectrum.

Listing 2.1

9700 REM sta rt


9701 REM IN : HORIZ, VERT
9702 REM OUT : NXPIX, NYPI X, XORIG, YORIG, XYSCALE, XPEN, YPEN
9710 LET XORIG = 0: LET YORIG = 0
30 Advanced Graphics with the Sinclair ZX Spectrum

9720 LET XPEN = 0 : LET YPEN = 0


9730 LET NXPIX = 256: LET NYPIX = 176
9740 LET XYSCALE = NXPIX/HORIZ: LET YSCALE = NYPIX/VERT
9750 IF XYSCALE > YSCALE THEN LET XYSCALE = YSCALE
9760 RETURN

This routine may be extended should we need colour; it must have two extra
parameters COLPAPand COLINK (integers between 0 and 7) for the colour of
the paper and ink respectively. The following extra statement should be added

9725 PAPER COLPAP : INK COLINK

If we need to write this routine for a different microcomputer, all that is


necessary is to replace the statements containing the Spectrum BASIC graphics
instructions with the equivalent routines for the new machine. Most of the other
routines in this book are independent of the structure of the Spectrum.
In 'start' and in many other routines that follow, it is necessary to transform
the x/y-coordinates of a point into their pixel equivalents, so we introduce the
two functions FN X and FN Y in listing 2.2.

Listing 2.2
9650 DEF FN X<Z) INT «XORIG + Z)*XYSCALE + 0.5)
9660 DEF FN Y(Z) INT «YORIG + Z)*XYSCALE + 0.5)

The next primitive routine (listing 2.3) is 'setorigin'. This enables us to move
the coordinate origin by an amount XMOVE horizontally and YMOVE vertically
(distances in the scale of the coordinate system), consequently adjusting the
(XORIG, YORIG) values. After such a move the plot pen moves to the pixel
equivalent of the new origin.

Listing 2.3
960~ REM setorigin
9601 REM IN : XORIG, YORIG, XMOVE, YMOVE
9602 REM OUT : XORIG, YORIG, XPEN, YPEN
961~ LET XORIG = XORIG + XMOVE: LET YORIG = YORIG + YMOVE
9620 LET XPEN = FN X(~)
963~ LET YPEN = FN y(~)
9640 RETURN

We shall be in a position to draw straight lines after we have produced two


further routines : 'moveto', which moves the plot pen to a pixel equivalent of.the
point in coordinate space at one end of the line, and 'lineto', which draws the
line by moving the plot pen from its present position (set by a previous call to
'setorigin', 'moveto' or 'lineto ') to the pixel equivalent of the point on the other
end of the line. listings 2.4 and 2.5 show 'moveto' and 'lineto' routines designed
specifically for the Spectrum. The 'lineto' routine includes statements that
From Real Coordinates to Pixels 31

initiate the machine-dependent BASIC pixel instructions for drawing a line (note
that PLOT is absolute and DRAW is relative); however, the 'moveto' routine is
machine-independent. Hence if you wish to implement these routines on a differ-
ent microcomputer you need only alter the 'lineto' routine.

Listing 2.4
950fl REM moveto
9501 REM IN : XPT, YPT
9502 REM OUT : XPEN, YPEN
9510 LET XPEN = FN X(XPT)
9520 LET YPEN = FN Y(YPT)
9530 RETURN

Listing 2.5
940fl REM Li neto
9401 REM IN : XPT, YPT, XPEN, YPEN
9402 REM OUT : XPEN, YPEN
9410 LET NXPEN = FN X(XPT)
9420 LET NYPEN = FN Y(YPT)
9430 PLOT XPEN,YPEN
9440 DRAW NXPEN-XPEN,NYPEN-YPEN
9450 LET XPEN = NXPEN: LET YPEN = NYPEN
9460 RETURN

In all but the most elementary machines, it is possible to set up these plotting
routines or their equivalents (and many more as our knowledge increases) in a
library file or backing store. Then there is no need to retype them explicitly into
each new program. On the Spectrum we can store them as files on audio-cassettes
(and MERGE them if necessary) . On the companion cassette to this book you
will find these routines as part of the 'lib 1' library .

Example 2.1
Identify a rectangle in Cartesian space, 30 units by 20 units, with the graphics
frame of the Spectrum. Then draw a square of side 15 units, centred in the
rectangle (figure 2.2a) .
We centre the square by moving the origin to (15 .0,10.0) and thus define the
corners of the square to be (±7.5, ±7.5). See listing 2.6.

Listing 2.6
10fl REM draw;r,g a square
109 REM setup i dent i f i e r s to graph ics routines.
110 LET start = =
970fl: LET set or i gi n 960fl: LET moveto = 950fl
: LET l i ne t o = 940fl
119 REM define graph ics area.
120 LET ~ORIZ = 30: LET VERT = 20
130 GO SUB sta rt
140 LET XMCVE = HORIZ*0.5: LET YMOVE = VERT*fl.5
150 GO SUB setor igin
159 REM jo in corners of square in order.
160 LET XPT = 7.5: LET YPT = 7.5: GO SUB movetc
32 Advanced Graphics with the Sinclair ZX Spectrum

170 LET XPT = -7.5: LET YPT = 7 .5: GO SUB Lineto


180 LET XPT = -7.5: LET YPT = -7.5: GO SUB Line t o
190 LET XPT = 7.5: LET YPT = -7.5 : GO SUB Line t o
200 LET XPT = 7.5: LET YPT = 7.5: GO SUB Lineto
210 STOP

(a) (b)
Figure 2.2

It is as well to note , at this juncture, that the order in which the points are
joined is critical. For example, if the coordinates of the second and third corners
of the square are interchanged then figure 2.2b will be drawn.
Next we write a primitive routine 'polygon' that uses the Spectrum line-
drawing instruction to draw such figures. The routine is given the NPOL vertices
of the polygon as arrays X and Y (the x-coordinate and y -coordinate). We also
give an example main program calling this routine (listing 2.7) .

Listing 2. 7

100 REV mai n pr ogram/ caLLing poLygon


110 LET start =
9700: LfT setor igin = =
9600: LET moveto 9500
: LfT l ine to =
941;l0: LET pol ygon =300
120 LET H0RIZ =
30: LET VERT = 20
130 GO SUB start
140 LET n~CVE = HORIZ*0.5: LET YMOVE = VERT*0.5
150 GO SUB set or i gi n
1 59 REM de c Lare and i nput ve r t i cES of poL ygon.
160 DIM X(50l: DIM Y(50l
170 I NPU T "TYPE NUfI6ER OF VERTICES ", NPOL
180 FOR I = 1 TO f;FOL
190 INPUT ("X("+ STR$ 1+") ");X(I),( "Y ( "+ STR$ 1+") " ) ; Y(I )
200 NEXT I
e
21 GO SU B c o l y go n
220 STOP
From Real Coordinates to Pixels 33

300 REM pol ygo n


301 REM IN ; NPOl., YO , YO
310 LET XPT = X( NPO L) ; LET YPT = Y(NPOL ) ; GO SUB moveto
319 REM j c i r, v er t i ce a of po l y qo n in or de r ,
320 fOR I = 1 TO NPOL
330 LET XPT = XO) ; l.ET VPT = YO): GO SUB l ineto
340 NE XT I
350 RE TUN

Exercise 2.1
If we are using the Spectrum then it is possible to draw pictures in a variety of
colours. But before drawing it is necessary to set the colour using the INK opera-
tion . Write a routine 'setcolour' with one integer parameter COLINK that
achieves this .

Exercise 2.2
In all the plotting routines above, the scale of the mapping (XYSCALE) is fixed
once and for all; and the horizontal and vertical scaling factors are identical.
There is no need to heed this convention : write a routine 'factor' that alters the
horizontal scale by FX and the vertical by FY. Naturally, this implies that we
now have to define two separate scales (XSCALE and YSCALE, say); and also,
of course, the 'start', 'set origin' , 'moveto ' and 'lineto' routines must be altered
(see also chapter 6).

Exercise 2.3
There is no reason for the x -axis and y-axis to be identified with the horizontal
and vertical respectively . In fact they need not even be mutually perpendicular.
Experiment with these ideas, which necessarily involveschanging all the plotting
routines 'start', 'moveto', etc .

Example 2.2
One of the first popular graphics packages was CalComp. This includes a number
of routines to draw axes and scales for the construction of graphs, and many
other useful subroutines. They are all based on a line-drawing routine named
'plot' (not to be confused with the Spectrum PLOT), which is central to the
package ; 'plot' has three parameters, two reals XPT and YPT, the coordinates of
a point in space, and the movement information MOVE,an integer whose value
is set to ±2 or ±3. This one routine may be used to replace all three of our
routines 'setorigin', 'moveto' and 'lineto'. If MOVEis negative, then a new co-
ordinate origin is fixed at the point (XPT, YPT) of the old coordinate system -
equivalent to 'setorigin'. When the absolute value of MOVEis 3, then the plot
head is moved without drawing a line - equivalent to 'moveto' : when it is 2,
then a line is drawn - equivalent to 'lineto'.
Naturally, even if we do not wish to implement the complete CalComp pack.
age, we can still implement the 'plot' routine in place of 'setorigin', 'moveto' and
'lineto'; and use it instead, in conjunction with the remaining routines mentioned
in this chapter - see listing 2.8 .
34 Advanced Graphics with the Sinclair ZX Spectrum

Listing 2.8
980~ REM pLot I CaLComp
9801 REM IN : XPT, YPT, XPEN, YPEN, XORIG, YORIG, MODE
9802 REM OUT : XPEN, YPEh, XORIG, YORIG
9810 LET NXPEN = FN X(XPT)
9820 LET NYPEN = FN Y(YPT)
983~ IF ASS (MODE) = 2 THEN PLOT XPEN,YPEN: DRAW NXPEN-XPEN,NYPEN-YPEN
9840 LET XPEN = NXPEN: LET YPEN = NYPEN
9850 IF MODE < ~ THEN LET XORIG = XOR IG + XPT: LET YORIG = YORIG + YPT
9860 RETURN

To demonstrate the use of these plotting routines we shall draw some simple
patterns. There are those who think that the construction of patterns is a frivol-
ous waste of time . Nevertheless, we consider it a very useful first stage in under-
standing the techniques of computer graphics. Often, patterns of an apparently
sophisticated design are the result of very simple programs. Quickly producing
such graphical output is an immediate boost to morale , and gives a lot of con-
fidence to the beginner. Furthermore, new designs are always in demand:
geometrical art is used for the covers of books and pamphlets and in advertising
literature. It can do no harm to initiate artistic ideas that will be of great use later
when we study the pictorial display of data. Patterns are also an ideal way of
introducing some of the basic concepts of computer graphics in a very palatable
way. Take the next example, which looks at the important role of trigonometric
functions (sine and cosine), and of angular measurement in radians! Remember
that rr radians is the same angular measure as 180 degrees.

Figure 2.3
From Real Coordinates to Pixels 35

Example 2.3
Figure 2.3, a very popular design, is constructed by joining each vertex of a
regular N-sided polygon (an N-gon) to every other vertex. N is not greater than
30 .
We set the origin at the centre of the design, and all the vertices at a unit
distance from the centre: the sizes of the HORIZ and VERT (3, 2.1) , are chosen
so that the design fits neatly on the screen. If one of these vertices lies on the
positive x-axis (the horizontal), then the N vertices are all of the form (COS
(ALPHA), SIN(ALPHA)), where ALPHA is an angle 21fI/N and I is chosen from
1,2, . .., or N. Here for the first time we see point coordinates being calculated
by the program, not explicitly typed in, as in listing 2.6. Furthermore, since the
program uses these values over and over again, it is sensible to store them in
arrays and access them when required by specifying the correct array index.
Note that in listing 2.9, if 1 0:;;; I 0:;;; J 0:;;; N, then the J th point is not joined to the
I th point ; the line will have already been drawn in the opposite direction .

Listing 2.9

100 RE M joining vert ices of reguLar N-gon


110 LET start = 9700: LET setorigin = 9600: LET moveto = 9500
: LET Lineto = 94~0
120 LET HORIZ = 3: LET VERT = 2.1
130 GO SUB sta rt
140 LET XMOVE = HORIZ*0.5: LET YMOVE = VERT*0.5
150 GO SUB se t or i gi n
160 DIM X(30): DIM Y(30)
169 REM setup vert ices of reguLar N-gon in arrays X and Y.
170 INPUT "TYPE VALUE OF N ";N
180 LET ALPHA = 0: LET ADIF = 2*PI/N
190 FOR I = 1 TO N
200 LET X(I) = COS ALPHA: LET Y(l) = SIN ALPHA
210 LET ALPHA = ALPHA + A~IF
220 NEXT I
229 REM j oi n poi nt I to poi nt J : 1<=I<J<=N.
230 FOR I = 1 TO N-1
24~ FOR J = 1+1 TO N
250 LET XPT = X(l): LET YPT = Y(I): GO SUB moveto
260 LET XPT = X(J): LET YPT = Y(J): GO SUB Lineto
270 NEXT J
280 NEXT I
290 STOP

There are two immediate observations to be made from this very simple
example. The first concerns resolution. Because the graphics frame is a discrete
matrix, then straight lines must be approximated by a sequence of pixels. Un-
fortunately, the resolution of the Spectrum, like most microcomputer graphics
systems, is low (that is, NXPIX and NYPIX are the order of hundreds) so the
lines appear jagged; even in higher-resolution devices (like microfilm plotters)
the same is true, but the sizes involved are so small that the jaggedness goes
unnoticed.
36 Advanced Graphics with the Sinclair ZX Spectrum

The second observation is that as N increases in listing 2.9, the outline of the
figure (the N·gon) approximates closely to a circle . Therefore we can use this
idea to write a routine 'circle!' (listing 2.10a), which draws a circle with radius
R about the centre (XCENT, YCENT) to give a picture similar to figure 2.4.
Note that we are using angles measured in radians; that is, we are incrementing
by 3/(R*XYSCALE) each time through the loop - a value that depends on the
radius and produces a reasonable circle without waste of effort. Note also that
since the vertices of the N·gon are only needed once, we do not store their values
but calculate them as required . Again, the limitation in resolution of the screen is
apparent on the circumference of the circle.

Figure 2.4

Listing 2.10a
3~~ REM ci rc Le1
301 REM IN : XCENT, YCENT, R, XYSCALE
31~ LET XMOVE = XCENT: LET YMOVE = YCENT : GO SUB setorig in
320 LET AOIF = 3/(R*XYSCALE)
33~ LET XPT = R: LET YPT = 0: GO SUB moveto
339 REM caLculate and join points (XPT,YPT) around the circLe.
340 FOR A = AOIF TO 2*PI STEP AOIF
350 LET XPT = R*COS A: LET YPT = R*SIN A: GO SUB Lineto
360 NEXT A
370 RETURN

Listing 2.1 Ob
400 REM circLe2
401 REM IN : XCENT, YCENT, R, XYSCALE
410 CIRCLE FN X(X CENT) , FN Y(YCENT),R*XYSCALE
420 RETURN

We saw that the Spectrum has a BASIC function CIRCLE that enables us to
draw a circle. So we can incorporate this in a primitive routine 'circle2' (listing
2.l0b) for drawing a circle, one that is necessarily more efficient than 'circle! ' .
Whenever we use such routines, we must be aware of any side-effects pro-
duced ; for example, has the origin or plot head been moved by the routine? For
From Real Coordinates to Pixels 37

example, listing 2.1Oa changes the position of both the origin and plot pen,
whereas listing 2.1Ob does not. It would therefore be sensible to add the follow-
ing line to the 'circle 1' routine

370 LET XMOVE=-XCENT: LET YMOVE=-YCENT: GO SUB setorigin : RETURN

Exercise 2.4
Write a routine to draw an ellipse of major axis A units (horizontal) and minor
axis B units (vertical). Note that a typical point on this ellipse has coordinates
(A cos ex, B sin ex) where 0 < ex < 27T. However, it must be remembered that, un-
like the circle, ex is not the angle made by the radius through the point with the
positive x-axis, It is simply a descriptive parameter.
Incorporate this routine in a program that draws a diagram similar to figure
2.5 . Here are two things to note: (1) there is no need for A to be greater than B;
and (2) observe the optical illusion of the two apparent white diagonal lines.
Another illusion can be seen in figure 23 - dark circles radiating out from the
centre of the pattern. The study of optical illusions is fascinating (see Tolansky,
1964) and it is a never-ending source of ideas for patterns. This exercise was
introduced because it leads the way to the general technique of drawing curves
(see chapters 3 and 6) .

. .---------
_.- ,
-,
.' -,~ - -

i .- - - ~ - ,

\. . '. .
./
I
I
I

I
/

.:

", - ...... --'


- -.......

Figure 2.5

Example 2.4
An extension of this idea, the natural next step , is the construction of a spiral.
Again the general form of the curve about the origin is (R cos ex, R sin ex) but now
ex varies between angles (3 to (3 + 2N7T, where (3 (the parameter BETA) is the initial
angle that the normal to the spiral makes with the positive x-axis , and N is the
38 Advanced Graphics with the Sinclair ZX Spectrum

number of turns in the spiral. The radius R is no longer a constant value, but
varies with the value of a : if RMAX is the outer radius of the spiral then R is
given by the formula

R = RMAX(a - (3)/2Nrr

Note that this routine, which centres the spiral at (XCENT, YCENT), causes no
side-effects because we reset the origin back to its original position before
leaving the routine.

Listing 2.11 a

300 REM spi ra L1


301 REM IN : XCENT, YCENT, RMAX, N, BETA
310 LET XMCVE = XCENT: LET YMOVE = YCENT : GO SUB setorigin
320 LET ADIF = PI/50: LET ALPHA = BETA
330 LET RDIF = RMAX/(N*100)
339 REM caLcuLate and join points (XPT,YPT) on the spiraL.
340 FOR R = RDIF TO RMAX STEP RDIF
350 LET XPT = R*COS ALPHA: LET YPT = R*SIN AlPHA: GO SUB Lineto
360 LET AlPHA = ALPH~. + ADIF
370 NEXT R
380 LET XMOVE = -XCENT: LET Y'lOVE = -YCENT : GO SUB setorigin
390 RETURN

Listing 2.11 b

300 REM ceLtic/spiraL


301 REM IN : XCENT, YCENT, RMAX, N, SIGN
310 LET XMOVE = XCENT: LET YMOVE = YCENT : GO SUB setorigi n
320 PLOT XPEN,YPEN
330 LET R = 0: LET RDIF = R~AX/(N*2): LET S = 1
339 REM construct the spiraL using DRAW to produce a series of semicircLes.
340 FOR I = 1 TO N*2
350 LET R = R + RDIF: LET XPIX = S*R*XYSCALE
360 DRAW XPIX,0,SIGN*PI
370 LET S = -S
380 NEXT I
390 RETURN

Exercise 2.5
Listing 2.11a produces a diagram similar to figure 2.6a (with XCENT = 0,
YCENT = 0, N = 4, BETA = 1 and RMAX = 3). What happens if you set RMAX
to -3? Use the routine in a program that generates figure 2.6c. Again note the
optical illusion when the observer's head is moved in a circle in front of the
diagram, keeping the horizontal (and hence also the vertical) direction parallel
with the original. The spirals appear to rotate about the centre!
From Real Coordinates to Pixels 39
Example 2.5
Spirals have been used in art and design for thousands of years ; however, most of
the ancient spirals were not true spirals but consisted of sequences of semicircles
(see Bain, 1972). Listing 2.11 b (a routine with input parameters RMAX, Nand
SIGN - the orientation value being ±1) enables us to draw such semicircular
spirals using the DRAW option, and so it is much more efficient than the accurate
method of listing 2.11a (for example, figure 2.6b).

-::~::~:::~

\\ ,/'~;:1 \1;~~
,~ .J""'))
."
... "'... --_· ...···· ..·/ / l l
" -,, . . ~ _ _.. - .... .l
\\.~:::?~~~~:::: :::: ~.,
"I ...

(a) (b)

/;;~-----.:~.

\
.1 \
.~.~
~-...... ~.,
.. ...
--:...- ' :.-'../'./'/
..
..
I; I
::.. 1'\ . . ~---...: - ._..J t .. t .. ...

~~~ ~:::::- -=:::-:.:...


(c)
Figure 2.6

Exercise 2.6
Follow the logic of listing 2.11b, and extend it so that the normal to the original
curve does not go along the x-axis but makes an angle BETA with it . In the Book
of Kells there are examples of triskeles, which are composed of a set of third-
circles joined in sequence. Experiment in constructing these and any other
variations on this method, such as quarter-circles, etc.
40 Advanced Graphics with the Sinclair ZX Spectrum

Example 2.6
Write a routine (listing 2.12) that draws diagrams similar to figure 2.7 .
Here we introduce the concept of an envelope. Instead of drawing a curve by
a sequence of small line segments (as in the circle of listing 2.9), we devise a
sequence of lines that are tangential to the curve. For example, the figure shows
four rectangular hyperbolae placed in the quarters of the plane.
N points are placed on each of the four arms (of unit length) that divide the
plane into the four quarters. The 4N points are therefore (±I/N, 0.0) and (0.0,
±I/N) where I = 1,2, .. ,N.

Figure 2. 7
Listing 2.12
100 REM exampLe of an enveLope
110 LET start = 9700: LET setorigin = 96e0
: L.ET moveto = 9500 : LET L ineto = 941110
120 LE1 ,",CRIZ = 3: LET VERT = 2.1
130 GO SUB start
140 LET XMOVE = HORIZ*0.5: LET YMOVE = VERT*0.5
1511l GO SUB setorigin
159 REM draw unit axes in graphics area.
160 INPUT "TYPE N "; N
170 LET XPT = =
1: LET YPT Ill: GO SUB moveto
180 LET XPT = -1 : LET YPT = 0: GO SUB Lineto
190 LET XPT = 0: LET YPT = 1: GO SUB Lineto
200 LET XPT = =
0: LET YPT -1: GO SUB l;~eto
208 REM produce N sets each of four po;nt s, one on each axis.
209 REM join the points of each se t in order.
210 FOR I = 1 TO N
220 LET 101 = IIN: LET 102 = (N + 1 - I)/N
230 LET XPT = 101 LET YFT = 0 GO SUB moveto
240 LET XPT = 0 LET YPT = 102 GO SUB l ineto
2511l LET XPT = - 101 LET YPT = 0 GO SUB l i ne t o
260 LET XPT = 0 LET YPT = -102 GO SUB Lineto
270 LET XPT = 101 LET YPT = 0 GO SUB L i ne t o
280 NEXT I
290 STOP
From Real Coordinates to Pixels 41

Exercise 2.7
Generalise this routine so that there is a variable number of arms, M, stretching
out from the origin and dividing the plane into equal segments.

Exercise 2.8
Draw a diagram similar to figure 2.8; the routine will have an integer parameter N.
It will calculate 4 N points {P(I) : I = 1, 2 , . . . , 4 N } around the edges of a square
of unit side, starting at a corner. There is one point at each corner and the points
are placed so that the distance between consecutive points is lIN . Then, pairs of
points are joined according to the following rule : P(I) is joined to P(J) for all
positive I and J less than or equal to 4N, such that J - 1 (subtraction modulo
4N) belongs to the sequence 1, 1 + 2, 1 + 2 + 3, .. . For example , if N is 10, then
P(20) is joined to P(2l), P(23) , P(26), P(30), P(35), P(l), P(8) and P(l6). The
outer square should be drawn , and hence if two points lie on the same side of
the square there is no need to jo in them by a line since it already exists as an
edge of the outer square. For example, P(20) is a corner , so it is on the same
edge as P(l6) and also P(2l), P(23), P(26) and P(30) .

Figure 2.8

Example 2.7
Emulate a Spirograph, in order to produce diagrams similar to figure 2.9.
A Spirograph consists of a cogged disc inside a cogged circle, which is placed
on a piece of paper. Let the outer circle have integer radius A and the disc integer
radius B. The disc is always in contact with the circle . There is a small hole in the
disc at a distance D (also an integer) from the centre of the disc, through which is
placed a sharp pencil point. The disc is moved around the circle in an anti-
clockwise direction, but it must always touch the outer circle; the cogs ensure
42 Advanced Graphics with the Sinclair ZX Spectrum

Figure 2.9

that there is no slipping. The pencil point traces out a pattern, which is complete
when the pencil returns to its original position.
Initially we assume that the centres of the disc and the circle and also the hole
all lie on the positive x-axis, the centre of the circle being the coordinate origin.
In order to emulate the Spirograph we need to specify a general point on the
track of the pencil point. We let a be the angle made with the positive x-axis by
the line joining the origin to the point where the circle and disc touch. The point
of contact is therefore (A cos a, A sin a) and the centre of the disc is ((A - B) cos
a , (A - B) sin a). If we let ~ be the angle that the line joining the hole to the
centre of the disc makes with the x-direction, then the coordinates of the hole are

((A - B) cos a + D cos ~ , (A - B) sin 0: + D sin ~)

The point of contact between the disc and circle will have moved through a
distance Aa around the circle, and a distance -BI3 around the disc (the minus
sign is because a and 13 have the opposite orientation). Since there is no slipping,
these distances must be equal, and hence we have the equation 13 = -(A/B)o:.
The pencil returns to its original position when both a and 13 are integer multiples
of 21T. When a = 2N1T, then 13 = -N(A/B)21T: hence the pencil point returns to its
original position for the first time when N(A/B) becomes an integer for the first
time; that is, when N is equal to B divided by the highest common factor of B
and A. The routine 'Euclid' (listing 2.13) uses Euclid's algorithm (see Davenport,
1952) to calculate the highest common factor (integer HCF) of two positive
integers A and B.
This function is used in the routine 'spiro' (listing 2.13), which calculates
the value of N and then varies a (ALPHA) between 0 and 2N1T in steps of 1T/I00 ;
for each a, the value of (3 (BETA) is calculated and then the general track is
drawn. Figure 2.9 was drawn by a call to 'spiro' with A = 12, B = 7 and D = 5.
The size of HORIZ and VERT must be chosen so that the figure fits on the
screen; in this case HORIZ = 30 and VERT = 20.
From Real Coordinates to Pixels 43

Listing 2.13
20 0 REM EueL id
201 REM IN : A, B
202 REM OUT : HCF
21 0 LET I = A: LET HCF= B
220 IF A < B THEN LET I = B: LET HCF =
A
230 LET J = I - INT (I/HCF)*H CF
240 IF J = iii THEN RETURN
250 LET I = HCF: LET HCF = J: GO TO 230

300 REM spi r o


301 REM IN : A, B, D
310 LET RIB = A - B: LET ALPHA = 0: LET ADIF = PI/50: LET AOB = A/B
3 20 GO SUB Eucl id: LET N = B/HCF: LET NC = 100*N
330 LET XPT = RAB + D: LET YPT = iii: GO SUB rr.cv et c
339 REM calculate and j oi n po i nts (XPT,YPT) on t he pat h of a Spirograph.
340 FOR I = 1 TO NO
3 50 LET ALPHA =ALPHA + ADIF
360 LET BETA = ALPHA*ACB
: 70 LET XPT = RAB*COS ALPHA + D*COS BETA
380 LET YPT = RAB*SIN ALPHA - D*SIN BEH
390 GO SUB l i re to
400 NEXT I
410 RETURN

It is evident from this example that drawing patterns is not so straightforward


as it appears. Even such a simple picture as figure 2.8 requires the mathematical
backup of Euclid. Progressing through computer graphics, we shall discover more
and more that it is essential to have at least an elementary knowledge of not only
coordinate geometry but also calculus, algebra, Euclidean geometry and number
theory. Be prepared to scour your local library (or pester your friendly neigh-
bourhood mathematician) for the necessary information.

Complete Programs

At this stage we shall group the listings 2.1 ('start'), 2.2 (two functions FN X
and FN V), 2.3 ('setorigin'), 2.4 ('moveto') and 2 .5 ('lineto') under the heading
'lib I ' . Later we shall replace listing 2.5 with listing 3.3 ('clip' and a new version
of 'lineto').

I. 'lib I ' and listing 2.6 ('drawing a square'): no INPUT data.


II. 'lib I ' and listing 2.7 ('main program ' and 'polygon'): requires the number
of vertices on a polygon, and their XIV coordinates in pairs (-15 ~ X ~
15 and -IO~Y~ 10).
III. 'lib I ' and listing 2.9 ('joining vertices of regular N-gon'): requires an integer
N~30.
IV. 'lib I ' and your own 'main program' (listing 2.7 will be useful as a model)
calling listings 2.lOa ('circle I ') and 2.1Ob ('circle2'). Each routine requires
44 Advanced Graphics with the Sinclair ZX Spectrum

the centre (XCENT, YCENT) and radius R. Choose these values so that the
figure is consistent with your values of HORIZ, VERT, XMOVE and
YMOVE. Try 30 ,20,15 and 10 respectively . As an example call 'circle 1'
with centre (I , -1), radius 8 and 'circle2 ' with centre (I , 2), radius 5.
V. 'lib l ' and your own 'main program' calling listings 2.IIa ('spiral1') and
2.1 lb ('celtic'). Each routine requires the centre (XCENT , YCENT),
maximum radius RMAX and number of turns in the spiral N. Listing 2.11 a
('spirall ') also requires an angle BETA, whereas 2.1 1b ('celtic') needs a
value SIGN, which is ± 1. Choose these values so that the figure is consistent
with your values of HORIZ, VERT, XMOVE and YMOVE (for example ,
30,20,15 and 10). For example , call 'spiralI ' with centre (1, - 1) , RMAX
=8, N =3 and BETA =2, and call 'celtic' with centre (1,2) , RMAX =5,
N =5 and SIGN =-1 . Also try SIGN =+1.
VI. 'lib 1' and listing 2.12 ('envelope') : requires a integer N, 2 ~ N ~ 30 .
VII. 'lib l ' and listing 2.13 ('Euclid' and 'spiro') : requires three integers A, Band
D, where A> B> D. Choose HORIZ, VERT , etc. , so that the diagram fits
on the screen: set XMOVE = HORIbO.5, YMOVE = O.5*VERT (for
'setorigin'), where both HORIZ and VERT are greater than 2*(A - B + D).
3 Two-dimensional Coordinate
Geometry

In chapter 2 we introduced the concept of the two-dimensional rectangular co-


ordinate system ; we defined points in space as vectors, from which we were able
to draw line segments between pairs of points . To be strictly accurate, a straight
line (or line for short) in two-dimensional space is not a finite segment, but
stretches off to infinity in both directions, and so we need to introduce ways of
representing a general point on such a line.
We are taught that the equation of a straight line is y =mx + c, the relation-
ship between the x-coordinate and y-coordinate of a general point on the line,
where m is the tangent of the angle that the line makes with the positive x-axis,
and c is the point of intersection of the line with the y -axis; that is, when x = 0
then y = c. This formula may be well known, but it is not very useful. What
happens if the line is vertical? m is infinite! A far better formula is

ay = bx + c

This allows for all possible lines: if the line is vertical, a is 0; (bla) is now the
tangent of the angle that the line makes with the positive x-axis, and the line
cuts the y-axis at (cia) , provided that a is not equal to zero, and the x-axis at
(-clb), provided that b is not equal to zero. The line is parallel to the y-axis if a
is zero, and to the x-axis if b is zero .
We shall frequently use this formulation of a line in the following pages; how-
ever, we now introduce another, possibly more useful, method for defining a line.
Before we can describe this new method we must first define two operations on
vectors (namely , scalar multiple and vector addition) , as well as describe another
required operation - the absolute value of a vector. Suppose we have two
vectors p , =(xl,Yd and p , =(X2'Y2), then
scalarmultiple kp , = (k X Xl ' k X Yl) , we multiply the individual coordinates
by some scalar value (that is, real) k .
46 Advanced Graphics with the Sinclair ZX Spectrum

vector addition PI + P2 = (XI + X2 , YI +Y2) , add the x-coordinates together,


and the j-coordinates together .
absolute value Ipi 1= y(xi +yi) is the distance of the point PI from the origin
(this is also called the length, and the amplitude of the vector) .
To deflne a line we first arbitrarily choose any two points on the line , again
we call them PI == (XI. YI) and P2 == (X2 , Y2)' A general point p(/l) == (x, y) is
given by the combination of scalar multiples and vector addition

(1 - /l)JI + /lP2 for some real value of /l

that is, the vector «(1 - /l) x XI + /l X X2, (1 - /l) X YI + /l x Y2). We place the
/l in brackets after P to show the dependence of the vector on the value of u.
Later when we understand the relationship more fully we shall leave out the (/l).
If 0 < /l < 1, then p(/l) lies on the line somewhere between PI and P2' For any
specified point p(/l) , the value of /l is given by the ratio

distance of p(/l) from PI


distance of P2 from PI

where the measure of distance is positive if p(/l) is on the same side of P I as P2 ,


and negative otherwise. The positive distance between any two vector points PI
and P2 is given by (Pythagoras)

See figure 2.1, which shows a line segment between points (-3, -1) == p(O) and
(3, 2)==p(1) : the point (1,1) lies on the line asp(2/3) . Note that (3, 2) is a
distance 3y5 from (-3, -1), whereas (1, 1) is a distance 2Y5 . From now on we
omit the (/l) from the point vector.

Example 3.]
Wecan further illustrate this idea by drawing the pattern shown in figure 3.1. At
first sight it looks complicated, but on closer inspection it is seen to be simply a
square, outside a square, outside a square, etc. The squares are getting successively
smaller and they are rotating through a constant angle. In order to draw the
diagram we need a technique that, when given a general square, draws a smaller
internal square rotated through this fixed angle. Suppose the general square has
four corners {(Xi. Yi) I i = 1, 2, 3, 4} and the ith side of the square is the line
joining (xi. Yi) to (Xi+l, Yi+l) , assuming additions of subscripts are modulo 4
(that is, 4 + 1 = 1). A general point on this side of the square, (xi. Yi), is given by
Two-dimensional Coordinate Geometry 47

In fact J,L :l - J,L is the ratio in which the side is bisected. If J,L is fixed and the four
points { (xi, yi) Ii = 1, 2, 3 ,4 } are calculated in the above manner, then the sides
of the new square make an angle ex = tan " ! [J,L/(l - J,L)] with the corresponding
side of the outer square. So, by keeping J,L fixed for each new square , the angle
between consecutive squares remains a constant ex. In listing 3.1 , which generat-
ed figure 3.1, there are 21 squares and J,L =0.1.

Listing 3.1
100 RE~ square outside square etc.
110 LET start = 9700: LET setorigin = 9600 : LET moveto = 9500
: LET Lineto = 94f.l0
120 LET HORIZ = 3: LET VERT = 2.1
130 GO SUB start
14111 LET XMOVE = HORIZ*0.5: LET YMOVE = VERT*0.5
15111 GO SUB setori gi n
16111 DIM X(4): DIM Y(4): DIM V(4): DIM W(4)
170 DATA 1,1,1,-1,-1,-1,-1,1
179 REM initiaLise first square.
18111 FOR 1=1 TO 4: READ X(l),Y(l): NEXT I
189 REM set fo?J vaLue and draw 20 squares.
19111 LET MU = 111.1: LET UM = 1 - MU
21110 FOR I = 1 TO 21
21118 REM join four vertices of square (X(J),Y(J» J=1:4.
21119 REM caLcuLate next four ver t i ce s. CVCJ),W(J» J=1:4.
210 LET XPT = X(4): LET YPT = Y(4): GO SUB moveto
22111 FOR J = 1 TO 4
230 LET XPT = X(J): LET YPT = Y(J): GO SUB Lineto
24111 LET NJ = J + 1: IF NJ = 5 THEN LET NJ = 1
25111 LET V(J) = UM*XCJ) + MU*XCNJ)
260 LET W(J) = UM*Y(J) + MU*YCNJ)
270 NEXT J
279 REM copy arrays V and W into X and Y.
28111 FOR J =1 TO 4
29111 LET X(J) =
VCJ): LET YCJ) = W(J)
300 NEXT J
310 NEXT I
320 STOP

It is useful to note that the vector combination form of a line can be re-
organised

When given in this new representation the vector PI can be called the base vector,
and (P2 - PI) can be called the directional vector . In fact any point on the line
can stand as a base vector; it simply acts as a point to anchor a line that is parallel
to the directional vector. This concept of a vector acting as a direction needs
some further explanation. We have already seen that a vector pair, (x, y) say,
may represent a point; a line joining the coordinate origin to this point may be
thought of as specifying a direction - any line in space that is parallel to this
line is defined to have the same directional vector. We insist that the line goes
48 Advanced Graphics with the Sinclair ZX Spectrum

Figure 3.1

from the origin towards (x, Y), the so-called positive sense ; a line from (x, y)
towards the origin has negative sense.
This dual interpretation of a vector, as a point or a direction , is used in the
following example.

Example 3.2
Draw a dashed line , with 13 dashes (and hence 12 spaces between dashes) from
point PI == (x I, Y d to P2 == (x 2, Y 2) ' This problem is solved by finding the 26
equi-spaced points on the line ; that is PI + i/25 (P2 - PI) where i varies from
o(at PI) to 25 (at P2)' We draw consecutively or move between neighbouring
points using the CalComp 'plot' (listing 2.8). There is no need to store the values;
we already have PI , so, by adding 1/25(P2 - pd each time, we can move through
all the required points (see listing 3.2).

Listing 3.2

10~ REM dashed Lines


110 LET start = 970~: LET pLot = 980~
120 LET HORIZ = 3 : LET VERT = 2. 1
13~ GO SUB sta rt
1~ LET XPT = HORIZ*~.5: LET YPT = VERT*0.5: LET MODE = -3
150 GO SUB pl ot
160 INPUT "TYPE X1 AND Y1 "iX1i", "iY1
170 INPUT "TYPE X2 AND Y2 ", X2i" , "iY2
179 REM move to first point.
180 LET XPT = X1: LET YPT = Y1: LET ~~DE = 3 : G0 SUB pLot
190 LET XD = (X2 - X1)/25: LET YD = (Y2 - Y1)/25
199 REM aLternateLy draw and move to ne xt 25 pc i r.ts on the Line.
20~ FOR I = 1 TO 25
210 LET XPT = XPT + XD: LET YPT = YPT + YD: LET MODE = 5 - MODE: GO SUB pLot
220 NEXT I
230 STOP
Two-dimensional Coordinate Geometry 49

Exercise 3.1
Experiment by drawing different types of dashed lines: for example, (a) the size
of the dash could be twice that of the space between; (b) the size of the dash
could be a fixed numerical value and the number of dashes unknown ; (c) the
dashes could vary in size, alternating between large and short dashes, where the
relationship between the types of dashes and the spaces could be input variables.

This base and direction representation is also very useful for calculating the
point of intersection of two lines, a problem that frequently crops up in two-
dimensional graphics . Suppose we have two lines p + uq and r + As, where
p == (Xl. Yl) , q == (X2' 12), r == (X3. Y3) and s == (X4' Y4) for -00 <p., A < 00. We
need to find the unique values of p. and Asuch that

p+p.q=r+As

that is, a point that is common to both lines. This vector equation can be written
as two separate equations
Xl -r u « X2 =X3 +A X X4 (3.1)
Yl + P. X Y2 = Y3 + A X Y4 (3.2)

Rewriting these equations we get

(3.3)
(3.4)

Multiplying (3.3) by Y4, (3.4) by X4 and subtracting we get

If (X2 x Y 4 - Y2 X X4) = 0 then the lines are parallel and there is no point of
intersection (p. does not exist), otherwise

(3.5)

and similarly

A = (X3 - xt} x 12 - (Y3 - yt} X X2


(3.6)
(X2 X Y4 - Y2 x X4)

The solution becomes even simpler if one of the lines is parallel to a coordin-
ate axis. Suppose this line is X =d, then we can set r == (d, 0) and s == (0, I),
which when substituted in equation (3.5) gives
50 Advanced Graphics with the Sinclair ZX Spectrum

and similarly if the line is y = d

/l=(d-Yd/Yz

Naturally if both lines are parallel then the denominator in these equations
becomes zero and we get an infinite result , because the two parallel lines do not
intersect.

Example 3.3
Find the point of intersection of the two lines (a) joining (1, -1) to (-1 , -3) and
(b) joining (1, 2) to (2, - 2).
The lines may be written

(1 -/l)(I,-I)+/l(-I,-3) - oo < /l < oo (3.7)


(1 - A)(I, 2) + A(2, - 2) -00 < A< 00 (3.8)

or when placed in the base/directional vector form

(1, -1) + /l(-2, - 2) (3.9)


(1,2) + A(2, -4) (3.10)

Substituting these values in equation (3.5) gives

/l = (1 - 1) x - 4 - (2 + 1) x 2 = -1/2
(-2 x-4-(- 2) x2)

whence the point of intersection is (1 , -1) - 1/2(-2, -2) == (2,0).

Exercise 3.2
Experiment with this concept of vector representation of two-dimensional space.
You can make up your own questions: it is easy to check that your answers are
correct. Consider example 3.2 . We know that (2, 0) lies on the first line because
we used the value /l = -1/2 : our answer is correct if it also lies on the second line ;
it does with A= 1/2.

Exercise 3.3
Write a program that reads in data about two straight lines (it can be either in the
form of equations , or in the base/directional vector form) and then calculates
their point of intersection (if any).
Two-dimensional Coordinate Geometry 51

Clipping

By now you will have realised that it is impossible to PLOT, or DRAW, to a


pixel (x, y) outside the graphics area, and thus we are limited to 0 ~ x ~ 255
and 0 ~ y ~ 175 . It is far too easy to stray inadvertently outside this area. In
fact when drawing two-dimensional and three-dimensional scenes it is common-
place to define scenes that cover an area greater than that allocated to graphics
on the Spectrum . So it is necessary to find an algorithm that will clip off all
exterior line segments without losing any that should be drawn.
We assume that the centre of the screen is given by the (non-pixel) point
(255/2 , 175/2) == (127.5,87.5) and thus the four corners of the graphics area
are (127.5 ± 127.5, 87.5 ± 87.5). Our problem reduces to calculating which part
(if any) of a line segment joining pixel point (XA, YA) to pixel point (XB, VB)
lies within the area. In order to simplify matters we redefine our pixel coordinate
system to let the centre of the screen be the origin, by subtracting the vector
(127 .5,87.5) from the coordinates of original points. The graphics rectangle
now has corners (±127.5, ±87.5). We extend the sides of the rectangle, thus
dividing space into nine sectors ; see figure 3.2, which also shows the graphics
area and the BORDER. In this diagram a number of different line segments have
been drawn to aid the explanation of the algorithm . Each point in space may
now be classified by two parameters IX and IY where

(1) IX =-1, 0 or +1 depending on whether the x-coordinate value of the point


lies to the left, on or to the right of the graphics area;
(2) IY =-1 ,0 or +1 depending on whether the y-coordinate of the point lies
below, on or above the graphics rectangle.

These values are calculated, when needed, inside the algorithm program .

If the two points at the end of the line segment - that is, (XA , YA) and
(XB, VB) - have parameters IXA and IYA, and IXB and IYB respectively, then
there are a number of possibilities to consider.
(i) If IXA = IXB =1= 0 or IYA = IYB =1= 0, then the whole line segment is outside
the rectangle and hence may be safely ignored; for example, line AB in figure
3.2 .
(ii) If IXA = IYA = IXB = IYB = 0, then the whole line segment lies in the
graphics area and so the complete line must be drawn; for example, line CD.
(iii) The remaining case must be considered in detail. If IXA =1= 0 and/or IYA =1= 0
then the point (XA, YA) lies outside the rectangle and so new values for XA and
YA must be found - to avoid confusion we will call these XA' and YA'. (XA ',
YA') is the point on the line segment nearer to (XA, YA) where the line cuts the
graphics area . The formula for this calculation was considered above; that is, the
intersection of a line with another line parallel to a coordinate axis. If the line
misses the rectangle, then we define (XA', YA') to be that point where the line
52 Advanced Graphics with the Sinclair ZX Spectrum

IX=-1 . IX=0 IX=+1 ....


+

>-
H

E ~

>-
H

r~


.. ~

Figure 3.2

cuts one of the extended vertical edges. If IXA = IYA =0 then (XA' , YA') ==
(XA, VA). The point (XB', YB') is calculated in a similar manner; see the algor-
ithm given by routine 'clip' in listing 3.3 . The required clipped line is that joining
(XA' , YA') to (XB', YB'). If the original line misses the rectangle then the
algorithm ensures that (XA' , YA') = (XB' , YB') and the new line segment
degenerates to a point and is ignored. For example, EF is clipped to E'F' , GH
is clipped to GH' (G = G') and IJ degenerates to a point I' = J'.
Thus 'clip ' takes the two pixel end points of the line , (XA, VA) and (XB, YB),
and transforms them into the centred system. It then discovers which of the
above three possibilities is relevant and deals with it thus : (i) exit the routine
immediately ; (ii) join the two points; or (iii) calculate the 'dashed' points and
join them with a line.
Listing 3.3 also includes a new version of 'lineto' routine that calls 'clip '
instead of PLOT and DRAW, thus enabling it to cope with the problem of join-
ing lines anywhere in space. From now on always use this new version of 'lineto'.
It will prove invaluable, especially in the study of three -dimensional objects .

Exercise 3.4
Use this altered routine in the programs of chapter 2. Choose values of HORIZ
and VERT in such a way that some lines in the diagrams go outside the graphics
area.
Two-dimensional Coordinate Geometry 53

Listing 3.3
841<1£) REM cLip
8401 REM IN XA,YA,XB,YB
8409 REM change coordinate system.
84121 LET XA = XA - 127.5: LET YA = YA - 87.5: LET XB = XB - 127.5
: LET YB = YB - 87.5
8419 REM fine: the sector vaLues of two points (XA,YA) AND (XB,YB).
84221 LET IXA = 0: IF ABS XA > 127.5 THEN LET IXA = SGN XA
84321 LET IYA = 21: IF ABS YA > 87.5 THEN LET IY~ = SGN YA
8440 LET IXB = 21: IF ABS XB > 127.5 THEN LET IXB = SGN XB
84521 LET IYB = 0: IF ABS YB > 87.5 TH£:N LET lYB = SGN YB
8459 REM points in same off-screen sector then return.
8460 IF IXA*IXB = 1 OR IYA*IYB = 1 THEN RETURN
8470 IF IXA = 0 THEN GO TO 8521~
8479 REM move 1'st point to nearer x-edge .
8480 LET XX = 127.5*IXA: LET YA = YA + (YB - YA)*(XX - XA)/(XB - XA)
: LET XA = XX
8490 LET IYA = 0: IF ABS YA > 87.5 THEN LET IYA = SGN YA
852121 IF IYA = 0 THE~j GO TO 85221
8509 REM move 1'st point to nearer y-edge.
8510 LET YY = 87.5*IYA: LET XA = XA + (Xe - XA)*(YY - YA)/(YB - VA)
: LET YA = YY
85221 IF IXB = Il THEN GO TO 85521
8529 REM move 2'nd point to nearer x-edge.
85321 LET XX = 127.5*IXB: LET YB = YA + (YE - YA)*(XX - XA)/(XB - XA)
: LET XB = XX
8540 LET ;''''B = 21: IF ABS YB > 87.5 THEN LET IYB = SGN YB
855Ui IF IYB = 0 Tfl EN GO TO 85721
8559 REM move Z'nc point to nearer y-edge.
8560 LFT YY = 87.5*II'B: LET ;(E: : XA + (XB - XA)*(YY - YA)/(YB - VA)
: LET YB = n
857Vr IF ABS (XA - XB) < 21.0212121211 AND ABS (Y,. - VB) < 21.21212121211 THEN RETURN
8579 RE~1 pl ot r.or-r cc i r.ci dent poi nt s ,
85821 LET XA = INT (XA + 128): LET YA = INT (YA + 88)
: LET XB = INT (XB + 128): LET YB = INT (YB + 88)
8590 PLOT XA,YA: DRAII XB - XA,YB - Y.\: RETURN
94021 REM Lineto/ cLipping
9401 REV IN : XPT,YPT,XPEN,YPEN
9401 REM OUT: XPEN,YPEN
941e: LET XA=XPEN: LET YA=YPEN
94221 LET X r [ ~ = F N X(XPT)
94321 LET YPEN=FN Y(YPT)
9440 LET XB=XPEN: LET YB=YPEN
94521 GO SUB cLip
9460 HUL' FN

Returning to the use of a vector (q == (x, y) :1= (0, 0), say) representing a
direction, we note that any positive scalar multiple kq, for k > 0, represents the
same direction and sense as q. (If k is negative then the direction has its sense
inverted). In particular, setting k = 1/ I q I produces a vector (x/V(x 2 +y2),
y/V(x 2 +y2)) with unit absolute value.
Thus a general point on a line, p + J.LQ, is a distance Illql from the base point
p, and if Iql = 1 (a unit vector) then the point is a distance 1111 fromp.
We now consider the angles made by directional vectors with various fixed
directions. Suppose that 0: is the angle between the line joining 0 (the origin) to
q == (x , y) , and the positive x-axis. Then x = IqI x cos 0: andy = Iq I x sin 0:; see
figure 3.3 - there are similar figures for the three other quadrants.
54 Advanced Graphics with the Sinclair ZX Spectrum

IQ I C O SO
Figure 3.3

If q is a unit vector (that is, I q I = 1) then q == (cos 0:, sin 0:). We note that sin 0: =
cos (0: - rr/2) for all values of 0:. Thus we can rewrite q = (cos 0:, cos (0: - rr/2»,
but 0: - rr/2 is the angle that the vector makes with the positive y-axis. Hence the
coordinates of a unit directional vector are called its direction cosines, since they
are the cosines of the angle that the vector makes with the corresponding positive
axes.
Before continuing , we should take a look at the trigonometric functions avail-
able in BASIC: SIN and COS, and the inverse function ATN. SIN and COS are
functions with one parameter (an angle given in radians) and one result (a value
between -1 and +1). The ATN function takes any value and calculates the angle
in radians (in the so-called principal range between -rr/2 and +rr/2) whose
tangent is that value.
This leads us to the problem of finding the angle that a general direction
q == (x, y) makes with the positive x-axis , which is solved by routine 'angle' given
in listing 3.4; 'angle' will be of great use in later chapters when we consider three-
dimensional space.

Listing 3.4

8800 REM angle


8801 REM IN : AX,AY
8802 REM OUT : THETA
8809 REM THETA is the angle made by line to (AX,AY) with +ve x-axis.
8810 IF ASS AX > 0.00001 THEN GO TO 8860
8819 REM l ine i s vertical.
8820 LET THETA = PI/2
8830 IF AY < 0 THEN LET THETA = THETA + PI
8840 IF ASS AY < 0.00001 TliEN LET lHFTA = 0
8850 RETURN
8859 REM line not ver tical so it has finite tangent.
8860 LET THETA = ATN CAY/AX)
8870 IF AX < 0 THEN LET THETA = THETA + PI
8880 RETURN
Two-dimensional Coordinate Geometry 55

Figure 3.4

Now suppose we have two directional vectors (a, b) and (c, d); for simplicity
we can assume that they are both unit vectors and they pass through the origin
(see figure 3.4). We wish to calculate the acute angle, 0::, between these lines.
From the figure we note that OA =y(a 2 + b 2 ) = I and OB =y(c 2 +d 2 ) = 1.
So by the Cosine Rule

AB2 = OA2 + OB2 - 20A x OB x cos 0:: = 2 x (1 - cos 0::)

But also by Pythagoras

AB2 = (a - C)2 + (b - di = (a2 + b 2 ) + (c 2 +~) - 2 (a x c + b x d)


=2 - 2 (a x c + b x d)
Thus a x c + b x d = cos 0::. It is possible that a x c + b x d is negative, in which
case cos"? (a x c + b x d) is obtuse and the required acute angle is rr - 0::. Since
cos (rr - 0::) = -cos 0::, then the acute angle is given immediately by cos" (I a x c
+ b x dl). For example, given the two lines with direction cosines (y(3/2), 1/2)
and (-1/2, - y(3/2», we see that a xc + b x d = - y(3/2) and thus 0:: = cos " !
(y(3/2» = rr/6. This simple example was given in order to introduce the concept
of a scalar product» of two vectors, (a, b) • (c, d) = a x c + b x d. Scalar product
is extendable into higher dimensional space (see chapter 7 for a three-dimensional
example) and it always has the property that it gives the cosine of the angle
between any pair of lines with directions defmed by the two vectors.

Curves: Functional Representation versus Parametric Forms

A curve in two-dimensional space can be considered as a relationship between x


and y coordirlate values, the so-called functional relationship. Alternatively the
56 Advanced Graphics with the Sinclair ZX Spectrnm

coordinates can be individually specified in terms of other variables or para-


meters , the parametric form.
We have already seen that a line (a circular arc of infinite radius) may be
expressed as ay = bx + c. If we rearrange the equation so that one side is zero
(that is, ay - bx - c = 0) then the algebraic expression on the left-hand side of
the equation is called a functional representation of the line and written

f(x,y)==ay - bx-c

All, and only, those points with the property f(x, y) = 0 lie on the curve. This
representation divides all the points in two-dimensional space into three sets,
namely f(x, y) = 0 (the zero set), f(x, y) > 0 (the positive set) and f(x, y) < 0
(the negative set). If the function divides space into the curve and two other
connected areas only (that is, any two points in a connected area can be joined
by a curvilinear line that does not cross the curve), then these areas can be
identified with the positive and negative sets defined by f . However, be wary,
there are many elementary functions (for example,g(x, y) = cos (y) - sin (x))
that define not one but a series of curves and hence divide space into possibly an
infinite number of connected areas (note g(x, y) = g(x + 2m1T,y + 2n1T) for all
integers m and n). So it is possible that two unconnected areas can both belong
to the positive set.
Note that the functional representation need not be unique . We could have
put the line in an equivalent form

f'(x,y)==bx +c -ay

in which case the positive set of this function is the negative set of our original,
and vice versa.
The case where the curve does divide space into two connected areas is very
useful in computer graphics, as we shall see in a study of two-dimensional and
(especially) three-dimensional graphics algorithms. For example, take the straight
line

f(x,y)==ay - bx-c

where a point (x 1, y.) is on the same side of the line as (x 2, 12) if and only if
f(xl> y.) has the same non-zero sign asf(x2, Y2)' The functional representation
tells us more about a point (x 1, Y 1 ) than just which side of a line it lies - it also
enables us to calculate the distance of the point from the line.
Suppose we have the above line, then its direction vector is (a, b). A line per-
pendicular to this will have direction vector (-b, a) (why? the product of the
tangents of two mutually perpendicular lines is -1: see McCrae, 1953). So the
point q on the line closest to the point p == (x 1, Y 1) is of the form
Two-dimensional Coordinate Geometry 57

q == (Xl, y.) + Jl(-b, a)

that is, a new line joining P to q is perpendicular to the original line. Since q lies
on this original line

[(q) = [«Xl ,Y 1) + Jl( -b , a)) = 0

and hence

Hence Jl = - [ (x 1. Y d/(a 2 + b 2 ) . The point q is a distance Jl x I(-b, a) Ifrom


(x 1. Y 1 ), which naturally means that the distance of (x I' Y 1 ) from the line is
Jl x v(a 2 + b2 ) = -[(Xl . Y1 )/v(a 2 + b2 ): the sign denotes on which side of the
line the point is lying. If a2 + b 2 = 1 then I[(x I, Y d I gives the distance of the
point (x 1, Y 1) from the line.
This idea leads us straight to a way of implementing convex areas; that is, an
area with the property that a straight line segment joining any two points within
the area lies totally inside the area . We limit our study to convex polygons, how-
ever, since it is obvious that any convex area may be approximated by a polygon,
providing it has enough sides.
Suppose we have a convex polygon with n vertices {Pi == (Xi ,Yi) Ii = I, ... ,
n } taken in order around the polygon either clockwise or anti-clockwise; we
shall call such a description of a convex polygon an oriented convex set of
vertices . The problem of finding whether such a set is clockwise or anti-clockwise
is considered in chapter 7. The n boundary edges of the polygon are segments of
the lines

where i = 1, ..., n, and the addition in the subscripts is modulo n (that is, n + j ==
< n). Try to explain why these formulae do actually describe the line
j for I ";;;'j
segments!
This systematic definition of the lines enables us to define the inside of the
convex area. Any given line segment, say the one joining Pi to Pi+l for some i, is
such that the points inside the body must lie on the same side of this line as the
remaining vertices of the polygon, in particular Pi+2' So the inside is given by

{(x, y) Isign of [i(X, y) = sign of [i(Xi+2, Yitd '* 0: i = 1, . .., n}


A point on the boundary is given by

{ (x, y) Ithere exists one t. or two if (x, y) is a corner, where


58 Advanced Graphics with the SinclairZX Spectrum

1 :<.j:<. n such that fj(x, y) = 0 and


sign of fi(x , y) = sign of fi(xf+2, Yi+2) =1= 0 : i =1= j and 1:<' i:<. n}

A point outside the area is defined by

{(x, y) I there exists one t. 1 :<.j:<. n such that


0=1= sign of fj(x, y) =1= sign of fj(Xj+2' Yj+2) =1= O}

Naturally the additions of subscripts are all modulo n.

Example 3.4
Suppose we are given the convex polygon with vertices (1 ,0), (5 ,2), (4, 4) and
(-2, 1) (see figure 3.5) . In this order the vertices obviously have an anti-clock-
wise orientation. Are the points (3,2), (1 ,4), (3, 1) inside, outside or on the
boundary of the polygon? What is the distance of (4 ,4) from the first line?

I ,~

~j
I S . .,:; ; .

--......... - ..; . o..'..·. ,


---·"--r--_:__ :'. -:-

,::.

Figure 3.5

[1 (x, y) == (5 - 1) x (y - 0) - (2 - 0) x (x - 1) == 4y - 2x + 2
[2 (x, y) == (4 - 5) x (y - 2) - (4 - 2) x (x - 5) == -y - 2x + 12
[3(x,y)==(-2-4)x (y-4) -(1-4) x (x-4)==-6y+3x+12
[4 (x, y) == (1 + 2) x (y - 1) - (0 - 1) x (x + 2) == 3y + x-I

Hence point (3, 2) is inside the body because [1 (3 , 2) =4 and [1 (4 , 4) = 10;


[2 (3,2) = 4 and [2 (-2,1) = 15; [3 (3,2) = 9 and[3 (1,0) = 15;[4 (3,2) = 8
and [4 (5, 2) = 10 - all with the same positive signs.
Point (1,4) is outside the body because [3 (1,4) = -9 and [3 (1,0) = 15 -
opposite signs.
Two-dimensional Coordinate Geometry 59

Point (3,1) is on the boundary because j', (3,1) = 0, fz (3,1) = 5, f3 (3,1) = 15


andf4 (3,1) = 5.
In fact there is no need to work out fi(Xi+2'Yi+2) for every i, they all have the
same sign so once we have calculated fl (X3, Y3) then we can work with this
value throughout.
(4,4) is a distance fl (4, 4)/~(42 + 22) = 1O/~20 =~5 .

Exercise 3.5
Imagine two convex polygons that intersect one another. The area of inter-
section is also a convex polygon . Use the methods mentioned in this chapter to
calculate the vertices of the new polygon .

Having dealt with the functional representation of a line, what about the
parametric form? We noted that this form is one where the x-coordinate andy-
coordinate of a general point on the curve are given in terms of parameter(s)
(which might be the x-value and the y-value themselves), together with a range
for the parameter. So we have already seen a parametric form of a line: it is
simply the base and directional representation

b + J.Ld = (XI, YI) + J.L(X2' Y2)


=(x I + J.L x X2 , Y I + J.L x "2) where _00 < J.L < 00

J.L is the parameter, and x I + J.L x X2 and Y I + J.L x Y 2 are the respective x -value
andy-value, depending only on variable J.L .
We can also produce functional representations and parametric forms for
most well-behaved curves. For example, a sine curve is given by f(x , y) =Y -
sin (x) in functional representation, and by (x, sin (x)) with - 0 0 <x < 00 in its
parametric form . The general conic section (ellipse, parabola and hyperbola) is
represented by the general function .

f(x, y) =a x x 2 + b X y2 + h x x x y + fx x + g x y + c

where coefficients a, b, c, f, g, h uniquely identify a curve. A circle centred at


the origin of radius r has a = b = I, f= g = h = 0 and C = _r2, whencef(x ,y) =
x 2 + yZ _ r 2 . All the points (x , y) on the circle are such that f(x, y) = 0, the
inside of the circle has f(x, y) < 0, and the outside of the circle f(x, y) > O.
The parametric form of this circle is (r cos a, r sin Q) where 0 ~ Q ~ 21T. (We
have already met the parametric form of a circle, ellipse and spiral in chapter 2).
It is very useful to experiment with these (and other) concepts in two-
dimensional geometry . There will be many occasions when it is necessary to
include these ideas in programs, as well as the ever-present need when generating
coordinate data for diagrams.
60 Advanced Graphics with the Sinclair ZX Spectrum

Examp/e3.5
Suppose we wish to draw a circular ball (radius r) disappearing down an elliptical
hole (major axis a, minor axis b), see figure 3.6. Parts of both the ellipse and
circle are obscured .
Let the ellipse be centred on the origin with the major axis horizontal, and
the centre of the circle a distance d vertically above the origin. The ellipse has
functional representation

and in parametric form

(a x cos a, b x sin 0:) with 0 ~ 0: ~ 21T

For the circle

and in parametric form

(r x cos A, d + r x sin X) where 0 ~ X ~ 21T

To generate the picture we must find the points (x, y) common to the circle and
ellipse (if any) . As a useful demonstration we shall mix the representations in
searching for a solution, using the functional representation for the circle and the
parametric form of the ellipse.
So we are searching for the points (x, y) == (a x cos a, b x sin 0:) on the
ellipse, which also satisfy I« (x,y) = O. That is

a2 x cos? 0: + (b x sin 0: - d)2 - r2 =0


2
and a x cos 2
0: + b x sin
2 2
0: - 2 x b x d x sin 0: + d 2 - r2 = 0

And since cos2 0: = 1 - sin2 0:

This is a simple quadratic equation in the unknown sin ex, which is easily solved
(the quadratic equation Ax 2 + Bx + C =0 has two roots (-B ± y(B 2 - 4 x A x
C»)/(2 x A)). For each value of sin 0: we can find values for 0: with 0 ~ 0: ~ 21T
(if they exist) and we can then calculate the points of intersection (a x cos Cl:,
b x sin 0:).
There is no hard and fast rule regarding which representation to use in any
given situation - afeel for the method is required and that comes only with
experience .
Two-dimensional Coordinate Geometry 61

Figure 3.6

Exercise3.6
Write a program that will draw figure 3.6.

Complete Programs

I. 'lib l ' and listing 3.1 : no data required.


II. Listings 2.1, 2.8 and 3.2: data are two coordinate pairs (Xl, YI) and
(X2, Y2), where - 3 < xi, X2 < 3 and -2.1 < YI, Y2 < 2.1.
Note: from this point listing 3.3 ('clip' and a new version of 'lineto') will
replace listing 2.5 in 'lib 1'.
III. The same as I above, but with the new 'lib I ' : change HORIZ to 1.5 and
VERT to 1.
4 Matrix Representation of
Transformations on Two-
Dimensional Space

In chapter 2 we saw the need to translat e pictures of objects about the screen.
Rather than perpetually change the screen coordinate system , it is conceptually
much easier to define an object in the most simple terms possible (as vertices in
the form of pixel or coordinate values, together with line and area information
related to the vertices), and then transform the object to various parts of the
screen while keeping the screen coordinate system fixed. We shall restrict our-
selves to linear transformations (see below). It will often be necessary to trans-
form a large number of vertices, and to do this efficiently we use matrices.
Before looking at such matrix representations we should explain exactly what is
meant by a matrix , and also by a column vector. In fact we restrict ourselves to
square matrices ; to 3 X3 (said 3 by 3) for the study of two-dimensional space,
and later we shall use 4 X 4 matrices when considering three-dimensional space.
Such a 3 X 3 matrix (A say) is simply a group of real numbers placed in a block
of3 rows byJ columns: a column vector (D say) is a group of numbers placed
in a column of 3 rows

A general entry in the matrix is usually written A i j , the first subscript denotes
the i th row, and the second subscript the/h column (for example ,A 2 3 repre-
sents the value in the second row, third column). The entry in the column vector,
D i , denotes the value in the i th row. All these named entries will be explicitly
replaced by numerical values and it is important to realise that the information
stored in a matrix or column vector is not just the individual values but also the
position of these values within the matrix or vector. Naturally BASIC programs
are written along a line (no subscripts or superscripts), and hence matrices and
vectors are implemented as arrays and the subscript values appear inside round
brackets following the array identifier.
Matrices can be added. Matrix C = A + B , the sum of two matrices A and B , is
defined by the general entry Ci j thus
Matrix Representation of Transformations on Two-dimensional Space 63

Matrix A can be multiplied by a scalar k to form a matrix B

B jj = k X A jj 1 ~ i, j ~ 3

We can multiply a matrix A by a column vector D to produce another column


vector E thus

Ej=A il X D l +A j2 X D 2 +A j3 X D 3= 'LA jkxDk where 1 ~i~3


k

The i th row element of the new column vector is the sum of the products of the
corresponding elements of the i th row of the matrix with those in the column
vector.
Furthermore, we can calculate the product (matrix) C = A X B of two mat-
rices A andB

Cjj = Ail X B l j + A j2 X B 2j + A j3 X B 3j = ~Ajk X B kj where 1 ~ i, j ~ 3


k

We take the sum (in order) of the elements in the i th row of the first matrix
multiplied by the elements in the jth column of the second . It should be noted
that the product of matrices is not necessarily commutative ; that is, A X B need
not be the same as B XA . For example

010
01\) (0010
01) (0100
10) (0001) (00010) (1001
00)
(o100 100 001 100 100 010
X = but lOX 1 =

Experiment with these ideas until you have enough confidence to use them in
the theory that follows . For those who want more details about the theory of
matrices we recommend books by Finkbeiner (1978) and by Stroud (1982).
There is a special matrix called the identity matrix I (sometimes called the
unit matrix)

1a a a0)
1=
(a a 1
1

Also for every matrix A we can calculate its determinant det (A)

det(A)=A ll x (An X A 33 -A 23 X A 32)+A 12 X (A 23 X A 31 -A 2l x A 33 )


+A 13 x (A 2l X A 32 -A 22 x A 3d
64 Advanced Graphics with the Sinclair ZX Spectrum

Any matrix whose determinant is non-zero is called non-singular, and with zero
determinant singular. All non-singular matrices A have an inverse A -1 , which has
the property that A X A-I = I and A-I X A = I . For methods of calculating an
inverse of a matrix see Finkbeiner (1978) ; we give a listing in chapter 7 (listing
7.5), which uses the Adjoint method.
Wenow consider transforming points in space. Suppose a point (x, y) -
'before' - is transformed to (x', y') - 'after'. We understand the transformation
completely if we can give equations relating the 'before' and 'after' points. A
linear transformation is one that defmes the 'after' point in terms of linear com-
binations of the coordinates of the 'before' point ; that is, the equations contain
only multiples of x, y and additional real values - it includes neither non-unit
powers or multiples of x and y, nor other variables. Such equations may be
written

x' = A 11 X X +A 12 X Y + A 13
y'=A 21 X x+A n Xy+A 2 3

The A values are called the coefficients of the equation. As we can see, the result
of the transformation is a combination of multiples of x-values, y-values and
unity . We may add another equation

For this to be true for all values of x and y, we see that A 31 = A 32 = 0 and
A 33 = 1. This may seem a pointless exercise but we shall see that it is very useful.
For if we set each point vector (x, y) (also called a row vector for obvious
reasons) in the form of a three-dimensional column vector

then the above three equations can be written in the form of a matrix multiply-
ing a column vector

So if we store the transformation as a matrix, we can transform every required


point by considering it as a column vector and premultiplying it by the matrix.
Many writers of books on computer graphics do not like the use of column
vectors. They prefer to extend the row vector (for example, (x, y) to (x, y, 1)),
Matrix Representation of Transformations on Two-dimensional Space 65

and postmultiply the row vector by the matrix so that the above equations in
matrix form become

A ll
(x',y' ,1)=(x,Y,1)X A 12
(
A 13

Note that this matrix is the transpose of the matrix of coefficients in the equa-
tions. This causes a great deal of confusion among those who are not confident
in the use of matrices. It is for this reason that in this book we keep to the
column vector notation. As you get more practice in the use of matrices it is a
good idea to rewrite some (or all) of the following transformation routines in
the other notation. It is not important which method you use finally, as long as
you are consistent. (Note the transpose B of a matrix A is given by B i; = A ji »
where 1 ~ i, j ~ 3.)

Combination of Transformations

A very useful property of this matrix representation of transformations is that if


we wish to combine two transformations on (say) transformation (= matrix) A
followed by transformation B, then the combined transformation is represented
by their product C =B X A : note the order of multiplication - the matrix
representing the first transformation is premultiplied by the second. This is
because the fmal matrix will be used to premultiply a column vector represent-
ing a point, and so the first transformation matrix must appear on the right of
the product and the last on the left. (If we had used the row vector method then
the product would appear in the natural order from left to right - this is the
price we pay for identifying the transformation matrix with the coefficients of
the equation.)
So we need to introduce a routine 'mult2', which forms the product of two
matrices. The BASIC computer language does not allow the transmission of array
parameters into routines, so we must invent an efficient means of coping with
this limitation. We assume that all matrix multiplication operates on matrices A
and R giving the product matrix B, and after the product is complete B is copied
back into R. The reason for the choice of identifiers and the fmal copy will
become evident as we progress. We also need a routine ('idR2'), which setsR to
the identity matrix. Should we need to form the product of a sequence of
matrices we first set R = I and then for each of the matrices from right to left,
we name each A and call the routine 'mult2' in turn . At the end of the process,
R contains the matrix product of the sequence (see listing 4.1).
66 Advanced Graphics with the Sinclair ZX Spectrum

Listing 4.1
9101' REM muL t2
9101 REM IN : A(3,3),R(3,3)
9102 REM OUT : R(3,3)
911 I' FOR I = 1 TO 3
9120 FO R J= 1 TO 3
9130 LET AR = 0
9140 FOR K = 1 TO 3
9150 LET AR = AR + A(I,K )*R(K, J)
9160 NEXT K
9170 LET B(I,J) = AR
9180 NEXT J
9190 NEXT I
9201' FOR I = 1 TO 3
9210 FOR J = 1 TO 3
9220 LET R(I,J) = B(I,J)
9230 NEXT J
9240 NEXT I
9250 RETURN

9301' REM idR2


9302 REM OUT : R(3,3)
9310 FOR I = 1 TO 3
9320 FOR J = 1 TO 3
9330 =
LET P. ( I ,J ) 0
9340 NEXT J
9350 LET R<I,1) = 1
9360 NEXT I
9370 RETURN

All natural transformations may be reduced to a combination of three basic


forms of linear transformation: translation , scaling and rotation about the co-
ordinate origin. It should also be noted that all valid applications of these
transformations return non-singular matrices. The routines that follow generate
a matrix called A for each of the three types of transformation, so that each
transformation routine can be used in conjunction with 'mult 2' to produce
combinations of transformations.

Translation

A 'before ' point (x, y ) is moved by a vector (TX, TY) to (x', y') say. This
produces the equations

x' = 1 x x + 0 x y + TX
y' = 0 x x + 1 x Y + TY

so the matrix describing this transformation is


Matrix Representation of Transformations on Two-dimensional Space 67

o1 01 TX)
TY
( 001

And a routine, 'tran2', for generating such a matrix A , given the values TX and
TY is given in listing 4 .2.
Listing 4.2
9000 REM tran2
9001 REM IN : TX,TY
9002 REM OUT : A(3,3)
9010 FOR I = 1 TO 3
9020 FOR J = 1 TO 3
9030 LET A(I,J) = 0
9040 NEXT J
9050 LET A(I,I) = 1
9060 NEXT I
9070 LET A(1,3) = TX: LET A(2,3) = TY
9080 RETURN

Scaling

The x-coordinate of a point in space is scaled by a factor SX, and the j-coordtn-
ate by SY, thus

x' = SX x x + 0 x y + 0
y' = 0 x x + SY x y + 0

giving the matrix

SX
oSY 0
0 0)
(
001

Usually SX and SY are both positive, but if one or both are negative this creates
a reflection as well as a scaling. In particular, -ifSX = -1 and SY = 1 then the
point is reflected about the y-axis. A program segment, 'seale2', to produce such
a scaling matrix A given SX and SY is given in listing 4.3.
Listing 4.3

8900 REM scaLe2


8901 REM IN : SX,SY
8902 REM OUT : A(3,3)
8910 FOR I = 1 TO 3
8920 FOR J = 1 TO 3
8930 LET A(I, J) = 0
8940 NEXT J
8950 NEXT I
8960 LET A(1,1) = SX: LET A(2,2) = SY
8970 LET A(3,3) = 1
8980 RETURN
68 Advanced Graphics with the Sinclair ZX Spectrum

Rotation about the Origin

Ifwe rotate a point in an anti-clockwise direction (the normal mathematical


orientation) about the origin by an angle 0 then the equations are

x' = cos 0 x x - sin 0 x y + 0


y ' = sin 0 x x + cos 0 x y + 0

and the matrix is

COS 0 -sin 0
sin 0 cos 0
(
o 0

The routine , 'rot2', to produce a rotation matrix, A, for an angle 0 is given in


listing 4.4 .

Listing 4.4
8600 REM rot2
8601 REM IN : THETA
8602 REM OUT : A(3,3)
8610 FOR I = 1 TO 3
8620 FOR J = 1 TO 3
8630 LET A(I,J) = 0
8640 NEXT J
8650 NEXT I
8660 LET A(3,3) = 1
8670 LET CT = COS THETA: LET ST = SIN THETA
8680 LET A(1,1) = CT: LET A(2,2) = CT
8690 LET A(1,2) = -ST: LET A(2,1) = ST
8700 RETURN

Inverse Transformations

For every transformation there is an inverse transformation that will restore the
points in space to their original position. If a transformation is represented by a
matrix A, then the inverse transformation is represented by the inverse matrix
A-I . There is no need to calculate this inverse using listing 7.5, we can find it
directly by using listings 4.2, 4.3 and 4.4, with parameters derived from the
parameters of the original transformation

(1) a translation by (TX , TY) is inverted by a translation by (-TX, -TY);


(2) a scaling by SX and SY is inverted by a scaling by IjSX and IjSY (naturally
both SX and SY are non-zero, for otherwise the two-dimensional space would
contract into a line or a point);
(3) a rotation by an angle 0 is inverted by a rotation by an angle -0;
Matrix Representation of Transformations on Two-dimensionalSpace 69

(4) if the transformation matrix is a product of a number of translation, scaling


and rotation matrices A X B X ex . . . X L X M X N (say), then the inverse
transformation matrix is

Note the order of multiplication!

The Placing of an Object

We are often required to draw a given object at various points on the screen, and
at arbitrary orientations. It would be very inefficient to calculate by hand the
coordinates of vertices for each position of the object and input them to the
program. Instead we define first an arbitrary but fixed coordinate system for
two-dimensional space, which we call the ABSOLUTE system. Then we give the
coord inates of the vertices of the object in some simple way , usually about the
origin, which we call the SETUP position . Lines and areas within the object are
defined in terms of the vertices . We can then use matrices to move the vertices of
the object from the SETUP to the ACTUAL position in the ABSOLUTE system.
The lines and areas maintain their relationship with the now transformed vertices.
The matrix that relates the SETUP to ACTUAL position will be called P through-
out this book (we sometimes give it a letter subscript to identify it uniquely from
other such matrices). Because of the restriction of not passing arrays as para-
meters into subprograms, we shall not normally explicitly generate array P,
instead it will be implicitly used to update the array R .

Lookingat the Object

Thus objects in a scene can be moved relative to the ABSOLUTEcoordinate


axes. When observing such a scene, the eye is assumed to be looking directly at
point (DX, DY) of the ABSOLUTE system and the head tilted through an angle
Q. It would be convenient to assume that it is looking at the origin and there is

no tilt of the head (we call this the OBSERVED position) . Therefore we generate
another matrix that will transform space so that the eye is moved from its
ACTUAL position to this OBSERVED position . The ACTUAL to OBSERVED
matrix is named Q throughout this book , and is achieved by first translating all
points in space by a vector (-DX, -DY), matrix A, and then rotating them by
an angle -Q, matrix B (note the minus signs!). Thus Q::: B X A, which is generat-
ed in routine '100k2', listing 4.5. Normally we do not calculate Q explicitly, as
usually it is used only to update R ; however, if it is necessary to use the values of
the matrix repeatedly then obviously it is sensible to store Q.
70 Advanced Graphics with the Sinclair ZX Spectrum

Listing 4.5
820~ REM Look2/ger.eraL
8202 REM OUT : R(3,3)
821~ INPUT "(DX,DY) ";DX;",";DY
8220 INPUT "ALPHA ";ALPHA
8229 REM Look at (DX,DY).
823~ LET TX = -DX: LET TV = -DY
8240 GO SUB tran2: GO SUB muLt2
8249 REM tiLt head through ALPHA rad ians.
8250 LET THETA = -ALPHA
8260 GO SUB rot2: GO SUB muL t2
8270 RETURN

Drawing an Object

Combining the SETUP to ACTUAL matrix P, with the ACTUAL to OBSERVED


matrix Q, we get the SETUP to OBSERVED matrix R = Q X P (we shall always
use R to denote this matrix : and remember R is always the result of our 'mult2'
routine). Transforming all the SETUP vertices by R, with the corresponding
movement of line and area information, means that the coordinates of the object
are given relative to the observer who is looking at the origin of the ABSOLUTE
coordinate system with head upright, and who is in fact really looking at a
graphics screen. So we identify the ABSOLUTE coordinate system with the
system of the screen to find the position of the vertices on the screen, and then
draw the vertices, lines and areas that compose the object. In practice this is
achieved by a construction routine that uses matrix R. It will set up the vertex,
line and area information, transform the vertices using R, and perhaps finally
draw the object (see example 4.1 below) . Later we shall see that there are
certain situations where it is more efficient to store the vertex, line and area
information. For example, the vertex coordinates can be stored in arrays X and
Y, and line information in a two-dimensional array L. Vertices can be stored in
their SETUP, ACTUAL or OBSERVED position - it really depends on the
context of the program. This SETUP to ACTUAL to OBSERVED method will
enable us to draw a dynamic series of scenes - objects can move relative to the
ABSOLUTE axes, and to themselves, while simultaneously the observer can
move independently around the scene. To start with, however, we consider the
simplest case of a fixed scene.

Complicated Pictures - the 'Building Brick' Method

We can draw pictures that contain a number of similar objects. There is no need
to produce a new routine for each occurrence of the object, all we do each time
is calculate a new SETUP to OBSERVED matrix and enter this into the same
routine. Naturally we shall require one routine for each new type of object in
the picture. The final picture is achieved by the execution of a routine we name
Matrix Representation of Transformations on Two-dimensional Space 71

'scene2' , which will be called from the standard main program (listing 4.6). This
main program simply defines the labels of the various subprograms , declares
arrays , centres the graphics area having INPUT HORIZ and VERT, and finally
calls 'scene2'.

Listing 4.6
10~ REM main pr 0g r ~m
1~9 REM def ine i de nt i f i er s for init iaLi sat i un and 2-D pLot routines.
110 LET start = 970~: LET se t ori gi n = 9600: LET moveto = 950~
: LET Lineto = 940~ : LET cLip = 840~
120 LET rot Z ~ E60~: LET angLe = 880~: LET scaLe2 = 890~: LFT t ran 2 = 90~0
: LET muLt2 = 9100: LET ; dR2 = 930~
130 LET scene2 = 600~: LET l cok2 = 820~
139 REM initiaLise and cent re graph ic s area.
140 INPUT "HORIZ ",HORIZ,"VERT ",VERT
150 GO SUB sta rt
160 LET XMOVE = HORIZ*0.5: LET YtlCVE = VERT*0 .5
170 GO SUB setorigin
139 REM set the scene.
180 GO SUB scene2
190 STOP

'scene2 ' will first call '100k2' and generate Q, and if more than one object is
to be drawn then we store it. For each individual object (or brick) we calculate a
matrix P and call the required construction routine using R = Q X P. All the
bricks finally build into the finished picture. To distinguish between different
occurrences of these matrices in what follows, we sometimes add a subscript to
the names P and R .
This modular approach to solve the problem of defining and drawing a
picture may not be the most efficient, but from our experience it does greatly
clarify the situation for beginners, enabling them to ask the right questions about
constructing a required scene. Also when dealing with animation we shall see
that this approach will minimise problems in scenes where not only are the
objects moving relative to one another, but also the observer himself is moving. .
Naturally if the head is upright then matrix Q can be replaced by a call to
'setorigin', which changes the screen coordinate system. Or if the eye is looking
at the origin, head upright , then Q is the identity matrix I; hence it plays no part
in transforming the picture and the '100k2' routine may be ignored. We shall
make no such assumptions and work with the most general situation : it is a use-
ful exercise throughout this book for the reader to cannibalise our programs in
order to make them efficient for specific cases. It is our aim to explain these
concepts in the most general and straightforward terms, even at the expense of
efficiency and speed. The reader can return to these programs when he is ready
and fully understands these ideas of transforming space. Later we shall give some
hints on how to make these changes, but at the moment this would only confuse
the issue.
However, the most important reason for this modular approach will be seen
when we come to draw pictures of three-dimensional objects . We shall define
72 Advanced Graphics with the Sinclair ZX Spectrum

these three-dimensional constructions as an extension of the ideas above , and full


understanding of two-dimensional transformations is essential before we go on
to higher dimensions.

Example 4.1
Consider a simple space ship SETUP pointing in the positive x -direction (that is,
making an angle 0 radians with the x-direction). The ship is defined by five line
segments joining, in order, the points (3, 0), (0 , 0) , (-1, 1), (2, 0), (-1 , -1) and
back to (0,0). See figure 4.1 ; which is a ship drawn on a screen 5 units by 3
units , where the SETUP to ACTUAL matrix is the identity and the ACTUAL to
OBSERVED matrix is such that the observer is looking at the point (1, 0) with
head upright. Listing 4 .7 gives the necessary routine 'scene2' that moves the
object into position, and listing 4.8 is the required construction routine 'ship'.
Note that 'ship', which uses matrix R to transform the vertices (and hence the
object) into their OBSERVED position, does not store the vertex values for this
position in a permanent data-base. Instead the values are kept in arrays X and Y
for the duration of the routine, and if the routine is re-entered to draw another
space ship then these array locations are used again.

~
~ -~'0)
(0
----------
10)/

/ / ------
.--
---------
/ /
/ "

~
(-1 1 - :1. )
Figure 4.1

Figure 4.2
Matrix Representation of Transformations on Two-dimensional Space 73

Listing 4. 7
60~~ REM sce ne2/l ook2 ; s~i~ ( n ct stored)
6010 DIM X(6): DIM V(6)
6020 DIM A(3,3): DIM B(3,3): DIM R(3,3)
6030 LET shi p =650~
6039 REM place the observer.
6040 GC SUB idR2: GO SUB look2
6049 REM def ine and draw oe j e ct .
6050 GO SUB shi p
6~60 RETU RN

Listing 4.8
650~ REM ship/ not stored
6509 REM IN : R(3,3)
6510 DATA 3,0,0,0,-1,1 ,2,0,-1,-1,0,0
6520 RESTORE sh ip
6530 FOR I = 1 TO 6
6539 REM read coordinates of SETUP object.
6540 READ XX, VV
6549 REM move object i nto OBSE RVED pos it ion.
6550 LET XCI) = XX*R (1,1) + VY*R( 1, 2) + R(1,3)
6560 LET V( I ) = XX*R(2,1) + VY*R( 2,2) + R(2,3)
6570 NEXT I
6579 REM join vertices in order.
6580 LET XPT = X(1) : LET VPT = Y(1): GO SUB moveto
6590 FOR I = 2 TO 6
660~ LET XPT = XCI ): LET VPT = Y(I): GO SUB l ineto
6610 NEXT I
6620 RETU RN

Example 4.2
Suppose we wish to draw figure 4.2, which includes four space ships labelled (a),
(b) , (c) and (d) on a screen 60 units by 40 units. For simplicity in this picture we
assume Q is the identity matrix, so the head is upright and the eye looks at the
SETUP origin. Ship (a) is placed identically to its SETUP position; that is,
R a =I , whereas ship (b) is moved from its SETUP to ACTUAL position by the
following transformations

(l) scale the figure with SX = 4 and SY = 2, producing matrix A ;


(2) rotate the figure through rr/6 radians, matrix B ;
(3) translate figure by TX = 6 and TY =4, matrix C

A =
(
4 0 0) (V3/2 - 1/2 0)
0 2 0 B = 1/2
(1 o
v'3/2 0 C = 0 1 4
6)
001 0 0 1 0 o 1

The complete transformation is given by R b = Q X Pb =I X Pb = Pb = ex B X A


(Note the order of matrix multiplication, and that the subscript distinguishes the
placing of ship (b) from the others).
If instead we used the order A X B X C (givingmatrix Pd), then
74 Advanced Graphics with the Sinclair ZX Spectrum

2Y3 -1 6) (2Y3 -2 12Y3-8)


Pb = 2 y3 4 Pd = 1 y3 4.j3 + 6
( o 0 1 0 0 1

which are two obviously different transformations. Matrix R d = Q X P d = I X P d


produces ship (d). Note how this ship is assymetrical. Be very careful with the
use of the scaling transformation - remember scaling is defined about the origin
and this will cause distortions in the shape of an object that is moved away from
the origin!
To illustrate this example further we show how to calculate the ACTUAL
position of ship (b) on the screen by setting the coordinates in the form of a
column vector and premultiplying them by matrix R b =I X P b ; for example

Y
(
2 3 -1 6)
~ ~3 1 X
(3)
~ = ~0
(6V3 + 6)
etc.

When returned to normal vector form we see that the five vertices have been
transformed to (6V3 + 6 ,10), (6, 4) , (5 - 2y3 , y3 + 2) , (4.j3 + 6, 8) and
(7 - 2y3, 2 - y3) respectively .
Ship (c) is ship (b) reflected in the line 3y = - 4x - 9. This line cuts the y-
axis at (0, - 3) and makes an angle 0: = cos"! (-3/5) = sin- 1 (4/5) = tan " !
(-3/4) with the positive x-axis. If we move space by a vector (0 , 3) , matrix D
say, th is line will go through the origin. Furthermore, if we rotate space by -0: ,
matrix E say , the line now is identical with the x -axis, Matrix F can reflect the
ship in the x-axis, £-1 puts the line back at an angle 0: with the x -axis, and
finally D - 1 returns the line to its original position. Matrix G = D- 1 X £-1 X
F X E X D will therefore reflect all the ACTUAL vertices of ship (a) about the
line 3y = - 4 x - 9, and R c =I XPc = G X Pb can therefore be used to draw ship
(c). That is, we use matrix Pb to move the ship to position (b) and th en G to
place it in position (c).

100) - 3/ 5 4/5
D=
(
0 1 3
001
£ =
(
- 4/5 - 3/ 5
o 0
and
1 ( -48 - 14.j3 7 - 24.j3 - 210)
Rc =- 14 -48y3 24+7y3 -170
25 0 0 25,

Figure 4 .2 is drawn using the new 'scene2' routine of listing 4.9 : note that
this 'scene2' does not call '100k2', since it is assumed that th e eye is looking at
the origin with the head erect. The main program and the 'ship' routine , as well
as all the other graphics package routi nes, sta y unchanged.
Matrix Representation of Transformations on Two-dimensional Space 75

Listing 4.9
60~0 REM scene2/ no Look2 ; 4 shi~s (net s t0r~L)
6010 elM X(6) : DI~ Y(6)
6020 DIM A(3,3): DI~ B(3,3) : DIM R(3,3)
6030 LET ship = 6500
6~39 REM OBSERVED=ACTUAL, no need to caLL 'Look2'.
6034 REM ship a).
6040 GO SUB i dR2 : GO SUB sh i p
6~49 REM sh ip b).
6050 LET SX = 4 : LET ~ Y = 2
6e60 GO SUB scaLe2: GO SUB muLt2
607e LET THETA " F!l6
6080 GO SUB rot2 : GO SUB muL t2
60ge LET TX " 6: LET TY = 4
6100 GO SUB tran2: GO SUB m~Lt2
611~ GO SUB sr ip
6119 REM ship c).
6120 LET AX " -3: LET AY = 4
6130 GO SUB angLe
6140 LET TX " 0: LFT TY " 3
6150 GO SUB tran2: GO SUB muLt2
616e LET T~ETA " -THETA
6170 GO SUB rot2: GO SUB muL t2
61Se LET SX = 1: LET SY = -1
6190 GO SUB sea Le2: G0 SUB n LiL t2
6200 LET THETA = -THETA
621 ~ GO SUB rct2: GO Sl'8 n.ul t2
6220 LET TX = 0: LET TY = -3
623~ GO SUB t rar2: GO SUB muLt2
6 2L.0 GO SUB shi p
6249 RE~ s hi p c).
6250 GO SUB i dR2
6260 LET TX = 6: LET n = 4
6 2 7~ GO SUB tran2: GO SUB muLt2
6280 LET TH ET F. = P!/6
(,290 GO SUB r et2 : GO SUB muL t2
6300 LET SX = 4: LET SY = 2
6310 GO SUB s ca Le2 : GO SUB muL :2
63?0 GC SU B s h i p
6330 RETUR'"

Exercise 4.1
In order to convince yourself that this program may be used to deal with the
general situation, you should run this program using non-zero values of DX, DY
or 0: so that the ACTUAL to OBSERVED matrix Q is not the identity matrix .
Your 'scene2 ' routine should call 'look2 ' to calculate Q, which must be stored .
Then for each object in the scene, in turn, calculate the SETUP to ACTUAL
matrix P (which 'mult2' places in R), premultiply it by Q (which has to be
copied into matrix A for use with 'mult2') and finally enter the construction
routine with the product matrix R = Q X P. Make sure that the 'lineto' routine
contains the 'clip' option or you will find your program fails when it tries to
draw outside the rectangle of the graphics area.
76 Advanced Graphics with the SinclairZX Spectrum

Exercise 4.2
Use the above routines to draw diagrams that are similar to figure 4.2, but where
the number, position and directions of the ships are read in from the keyboard.
You can produce routines to draw more complicated objects; we chose a very
simple example so that the algorithms would not be obscured by the complexity
of objects. The above method can deal with as many vertices and lines as the
Spectrum can handle within time and storage limitations. The objects need not
be line drawings only, you can draw coloured areas (polygons bounded by
transformed vertices).

Exercise 4.3
Using loops in the program we can draw ordered sequences of the objects; for
example, they can all have the same orientation but with points of reference
(the origin in the SETUP position) equally spaced along any line p + uq, We can
set up a loop with index parameter IJ. and draw one ship for each pass through
the loop . For each value of IJ. we can alter the parameters of translation in a
regular way within the loop (using IJ., p and q). The new values of these para-
meters are used to calculate a different SETUP to ACTUAL matrix for each
occurrence, and this moves the object into a new ACTUAL position. R = Q X
P = I X P is used to observe and draw each object on the screen . With these ideas,
construct a set of battle formations of the above type of ship on the screen .

Efficient Use of Matrices

It is obvious that whatever combination of transformations we use , the third row


of every matrix will always be (0 0 1). If we work with the top two rows of
the matrix only , it will make our routine much more efficient. We still keep
3 X 3 matrices rather than 2 X 3 (which is really all we need), because we may
have previously written other routines that assume 3 X 3 matrices. ReDIMension-
ing the arrays could lead to array bound errors in the earlier routines - the cost
of an extra three real numbers per matrix is a small price to pay to avoid errors.
Also note that when we DIMension an array it is immediately set to zero (see
page 202 of the Spectrum BASIC Handbook (Vickers (1982)). We rewrite list-
ings 4.1,4.2,4.3 and 4.4 as listings 4.1a, 4.2a, 4.3a and 4.4a respectively, to
making use of these facts .

Listing 4.1a

910£l REM mult2


9101 REM IN : A(3,3),R(3,3)
9102 REM OUT : R(3,3)
911£l FOR I = 1 TO 2
9120 FOR J = 1 TO 3
913£l LET B(I,J) = A(I,1)*R(1,J) + A(I,Z)*R(Z,J)
914lo! NEXT J
Matrix Representation of Transformations on Two-dimensional Space 77

9150 LET 8{I,3) = BCI,3) + A{I,3)


9160 NEXT I
9170 FOR J = 1 TO 3
9180 LET R{ 1,J)= B{1,J): LET RC2,J) = BC2,J)
9190 NEXT J
920rl RETURN

930rl REM idR2


9302 RE~ OUT: RC3,3)
931rl DIM R{3,3)
9320 LET H<1,1l =
1: LET RC2,2) =1
9330 RETURN

Listing 4.2a
90rlrl REM tran2
90rl1 REM IN : TX,TY
90rl2 REM OUT : A{3,3)
9010 DIM AC3,3)
9020 LET AC1,1l = 1 : LET AC2,2) = 1
9030 LET AC1,3) = TX: LET AC2,3) =
TY
9040 RETURN

Listing 4.3a
8900 REM sea Le2
8901 REM IN : SX, SY
8902 REM OUT : A{3,3)
8910 DIM AC3,3)
8920 LET AC1,1) = SX: LET AC2,2) SY
8930 RETURN

Listing 4.4a
860rl REM r ot 2
8601 REM IN : THETA
8602 REM OUT : A{3,3)
8610 DIM A{3,3)
8620 LET CT = COS THETA: LET ST =
SIN THETA
8630 LET A{1,1) = CT: LET AC2,2) =
CT
8640 LET AC1,2) = -ST: LET AC2,1) = ST
8650 RETURN

The construction of figure 4 .2 may seem rather contrived since the position
of the objects was chosen in an arbitrary way. However, in most diagrams the
positioning of objects will be well defined, the values being implicit in the
diagram required. See the example below.

Example 4.3
Write a program that draws an ellipse with major axis A, minor axis Band
centred at the point (CX, CY). The major axis makes an angle 8 with the positive
x-direction, Note that the order of transformations is important: first rotate and
then translate. If we wish to draw ellipses with major axishorizontal then we need
not use matrices, we can stay with the routine set in exercise 2.5 using ideas
78 Advanced Graphics with the Sinclair ZX Spectrum

similar to those in listing 2.9. Listing 4.10 gives a 'scene2' routine that reads in
data about the ellipse, calculates the SETUP to OBSERVED matrix and then
calls the construction routine 'ellipse' that draws the ellipse.

Listing 4.10
6000 REM scene2/ell ipse
6010 DIM A(3,3): DIM B(3,3): DIM R(3,3)
6020 LET e ll ipse = 6500
6030 INPUT "(Cx,cn "; CX; ","; CY,, "A ";A;",B ";B;", THETA "; THETA
6040 LET THFTA = -THETA
6049 REM ell ipse centred at (CX,CY) and til ted through angle THETA.
6050 GO SUB idR2
6060 GO SUB rot2: GO SUB mult2
6070 LET TX = CX: LET TY = CY
6080 GO SUB tran2: GO SUB mult2
6090 GO SUB ell ipse
6100 RETURN
6500 REM ell i pse
6501 REM IN : A,B,R(3,3)
6509 REM ellipse, major axis A, minor axis B.
6510 LET XPT = A*R(1,1) + R(1,3)
6520 LET YPT = A*R(2,1) + R(2,3)
6530 GO SUB moveto
65~ LET ALPHA = 0: LET ADIF = PI/100
6549 REM calculate point s (XPT,YPT) on ellipse, in OBSERVED pos ition.
6550 FOR I = 1 TO 200
6560 LET ALPHA = ALPHA + ADIF
6570 LET AA = A*COS ALPHA : LET BB = B*SIN ALPHA
6580 LET XPT = AA*R(1,1) + BB*R(1,2) + R(1,3)
6590 LET YPT = AA*R(Z,1) + BB*R(2,2) + R(2,3)
6600 GO SUB l ineto
6610 NEXT I
6620 RETURN

Exercise 4.4
Write a routine for drawing an individual matrix-transformable object (in this
case an astroid, shown in figure 4.3a) and then use the matrix techniques to
draw combinations of these objects (as in figure 4.3b). An astroid is a closed
curve with parametric form (R cos3 () fsin 3 ()) where 0";; () ..;; 21T, R being the
radius (the maximum distance from the centre of the object). The parameters
needed by this routine are the radius of the astroid and the transforming matrix.
Figure 4.3b is the combination of a large number of two different forms of the
astroid. One has radius 1 and is not rotated, the other has radius .J2 and is
rotated through rr/4 radians.

Exercise 4.5
Experiment with these matrix techniques. Write a subroutine that generates the
matrix necessary to rotate points in space by an angle () about an arbitrary point
(X, Y) in space (not necessarily the origin) . Also produce another routine that
generates the matrix that will reflect points about the general line ay =bx + c.
(Use the ideas given in example 4.2 for the production of ship (c).)
Matrix Representation of Transformations on Two-dimensional Space 79

.-----/
..
/
/
,J

~ ;/
\/1
(a) (b)
Figure 4.3

Storing Information about Scenes

We mentioned earlier that certain situations arise where we need to store all the
information about a scene in a large data-base rather than lose the information
on leaving the construction routine. Our data-base will consist of arrays X and Y,
of length greater than or equal to NOV, the final number of vertices to be stored .
(These vertices can be stored in the SETUP, ACTUAL or OBSERVED position:
it depends on the context of the problem.) We also need to store information on
lines , in a two-dimensional array L whose first index is 1 or 2, and whose second
index is a number between 1 and a value greater than or equal to NOL, the final
number of lines in the scene. The Ith line joins the two vertices with indices
L(l,l) to L(2,I) : hence this information is independent of position, it simply
says which two vertices are joined by the Ith line. NOV and NOL are initialised
in the 'scene2 ' routine and incremented in the construction routines.
We now no longer require construction routines to draw lines, we use them
only to create the data-base of lines, vertices, etc. (transformed by the matrix R) .
After 'scene2' has constructed the final scene in memory it calls another routine
'drawit', which draws the final picture. The 'scene2' routine will be very similar
to those mentioned earlier ; for example, the routine for drawing figure 4.2 in
this new way will be that given in listing 4.9 with the three minor changes
listed below
6010 DIM X(20): DIM Y(20): DIM L(2,20)

6030 LET NOV=O : LET NOL=O: LET ship= 6500: LET drawit=7000

6330 GO SUB drawit : RETURN


80 Advanced Graphics with the Sinclair ZX Spectrum

This is used in conjunction with listing 4.11, which gives the 'ship' construction
routine (which only sets up the data), and 'drawit ' routine.

Listing 4.11

650~ REM ship/ stored


6501 REM IN : NOV,NOL,R(3,3),X(NOV),Y(NOV)
6502 REM OUT: NOV,NOL,X(NOV),Y(NOV),L(2,NOL)
6510 DATA 3,0,0,0,-1,1,2,0,-1,-1,1,2,2,3 ,3,4,4,5,5,2
6520 RESTORE ship
6530 LET NV = NOV
6531 REM read vertices, and move i nt o pos ition using matrix R.
6540 FOR I = 1 TO 5
6550 READ XX,YY
6560 LET NOV = NOV + 1
6570 LET X(NOV) = XX*R(1,1) + YY*R(1,2) + R(1,3)
6580 LET Y(NOV) = XX*R(2,1) + YY*R(2,2) + R(2,3)
6590 NEXT I
6531 REM read and store line information
660~ FOR I = 1 TO 5
6610 READ L1,L2
6620 LET NOL = NOL + 1
6630 LET L(1,NOL) = L1 + NV: LET L(2,NOL) = L2 + NV
664f1J NEXT I
6650 RETURN
7~00 REM drawit
70~1 REM IN : NOL,X(NOV),Y(NOV),L(2,NOL)
7~09 REM draw line by jo in ing pa ir s of vert ices.
7010 FOR I = 1 TO NOl
7020 LET L1 = l(1,I): LET L2 = L(2,I)
7030 LET XPT = X(L1): LET YPT = Y(L1): GO SUB moveto
7040 LET XPT = X(L2): LET YPT = Y(L2): GO SUB l ineto
7~50 NEXT I
7060 RETURN

Suppose we wish to produce different views of the same scene (again we use
figure 4.2 as an example); that is, the same SETUP to ACTUAL matrices P, but
different ACTUAL to OBSERVED matrices Q. The obvious solution is to create
a data-base for the scene with the vertices in the ACTUAL position. Now for each
new OBSERVED position we calculate Q and enter it into another 'drawit'
routine (see listing 4.12 - different from listing 4.11), which transfers each
vertex from its ACTUAL to OBSERVED position using Q, stores them in arrays
V and W, and recalls them when they are required for drawing. When using this
method to construct different views of figure 4 .2, only the 'scene2' and 'drawit'
routines differ from their earlier manifestations, and then only slightly. We give
them in listing 4.12.
Matrix Representation of Transformations on Two-dimensional Space 81

Listing 4.12

6000 REM scer ~21 varia bLe Lock2 ; 4 ! hi ps l s t ore d)


6009 REM construct 4 shi ps s t o r e ~ in ACTUAL pos iti on.
6010 DIM XlZ0 ) : ~I M YI 2 ~) : DI~ V(20): DIMW(20) : DIM L(2,20 )
6020 DIM AI3,3): DIM BI3,3 ): DIM RI3,3)
603~ LET ~ hi ~ = 6500: LET draw it = 7000
6039 R~M ship a ).
6040 LET NOV = 0: LET NOL 0: GO SUB idR2 : GO SUB ship
6049 REM ship b).
6050 LET SX = 4: LET ~Y 0 2
606111 GO SUB s ca Le2 : GO SUB muLt2
6070 LET Tr El A = PI/6
6080 GO SUB rot2: GO SUB muL t2
6090 LET TX = 6: LET TY = 4
6100 GO SUB t ran2: GO SUB "'lIL t 2
6110 GO SUB ship
6119 REM ship c).
6120 LET AY = -3: LET AY = 4
6130 GO SUB angLe
61~ LET TX = 0: 1.<T TY = 3
6150 GO SUB tran2: GO SUB muL t 2
6160 LET THETA = -THETA
6170 GO SUB rot2: GO SUB muL tZ
6180 LET SX = 1: LET SY = -1
6190 GO SUB scaLe2: GO sun mlilt2
6200 LET THETA = -THETA
6210 GO sue r et2 : GO SUB muL t2
6220 LET TX = 0: LET TV = -3
6230 GO SUB tran2: GO SUB muLt2
6240 GO SUB ship
6249 REM ship d).
6250 GO SUB idR2
6260 LET TX = 6: LET ,.,. = 4
6270 GO SUB tran2: GO SUB mult2
6280 LET rsrr A = PI/6
6290 GO SUB rot2: GO SUB muL t2
6300 LET SX = 4: LET SY = 2
6310 GO SUB seaLe2: GO SUB ~ u Lt ~
t~20 GO SUB ship
6329 REM Loop th rough cbse rv at ' ( I r. poi nts.
6330 GO SUB idR2: GO SUB Look2
63~ CLS: GO SUB drawit
6350 GO TO 6330
6360 RETURN
7000 REM draw i t
7001 REM IN : NOV,NOL,RI3,3),XlNOV),LI2,NOL)
7009 REM transform ver t i ce s from ACTUAL to OBSERVED position.
7010 FOR I = 1 TO NOV
7020 LET VO) = XlIl*RI1,1l + YlIl*RI1,2) + RI1,3)
7030 LET WlI) = XlI)*RI2,1) + YlI)*RI2,2) + RI2,3)
70~ NEXT I
7049 REM d r a ~ Lines by joini ng pairs of vertices.
7050 FOR ! = 1 TO NOL
7060 LET L1 = LI1,I): LET L2 = LI2,I)
7070 LET XPT VlU): LET YPT WlL1): GO SUB mov et c
7080 LET XPT = VlL2): LET YPT = WlL2): GO SUB Line t o
7090 NEXT I
7100 RETURN
82 Advanced Graphics with the Sinclair ZX Spectrum

Exercise 4.6
Construct a dynamic scene. With each new view the ships will move relative to
one another in some well-defined manner. The observer also should move in
some simple way; for example, the eye starts looking at the origin, five views
later it is looking at the point (10 ,10), and with each view the head is tilted a
further 0.1 radian. You no longer need to INPUT the values of (DX, DY) and
ALPHA into 'look3' , instead they should be calculated by the program . After
you have read chapter 13 you can place these five pictures in store and recall
them as a 'movie' (if you have the 48K machine).

Exercise 4.7
Construct a scene that is a diagrammatic view of a room in your house - with
schematic two-dimensional drawings of tables , chairs, etc. placed in the room .
Each different type of object has its own construction routine, and the 'scene2'
routine should read in data to place these objects around the room. Once the
scene is set produce a variety of views, looking from various points and
orientations.
Or you can set up a line-drawing picture of a map, and again view it from
various orientations. The number of possible choices of scene is enormous!
Because we are using the 'clip' option in 'lineto' we can choose small values
for HORIZ and VERT, which has the effect of the observer zooming up close to
parts of a scene, and all external lines will be conveniently clipped off.

Complete Programs

We group the listings 3.4 ('angle'), 4.1a ('mult2' and 'idR2'), 4.2a ('tran2'),
4.3a ('scale'), 4.4a ('rot2 ') , 4.5 ('look2') and 4.6 ('main program') under the
heading 'lib2'.

I. .'lib l " 'lib2' , listings 4.7 ('scene2') and 4.8 ('ship'). Data required : HORIZ,
VERT, DX, DY and ALPHA. Try 8,5, 1, 1,0.5. Keep any four of these
values fixed and systematically make small changes in the other data value.
II. 'lib 1" 'lib2', listings 4.9 ('scene2') and 4 .8 ('ship'). Data required: HORIZ,
VERT. Try 30, 20; 200, 200 ; 200 ,150.
°
III. 'lib 1" 'lib2' and listings 4.1 ('scene2' and 'ellipse'). Data required: HORIZ,
VERT , CX, CY, A, B, THETA. Try 30, 20, 0, 0,12,9,0. Again fix all but
one of the values and change the remaining value systematically.
IV. 'lib 1" 'lib2' , listings 4.9 ('scene2' adjusted as per text) and 4.11 ('ship' and
'drawit'). Data required : as for II above.
V. 'lib1" 'lib2', listings 4.11 ('ship' but not 'drawit') and 4.12 ('scene2' and
'drawit ') . Data required: HORIZ, VERT, DX, DY, ALPHA. Try 60, 40, 0, 0,
0. Systematically change each of the data values in turn .
5 Character Graphics on the ZX
Spectrum

In the first chapter (listing 1.2) we saw how a small block or character may be
generated by eight binary numbers. Such a block of 8 by 8 pixels is known as a
character block . The Spectrum has three types of characters built in: the 96
character standard set, the 16 character block graphics set and the 21 character
user-defined graphics set. The latter two sets are accessed from the keyboard in
graphics mode . These characters are placed on the display when PRINT is used,
so we must take a closer look at this operation .
The PRINT command allows us to place characters on any of the 22 lines of
the upper screen, from top (0) to bottom (21), and at any of 32 positions along
each line, from left (0) to right (31). These are the character blocks and each
contains eight lines of eight pixels . Each line of eight pixels corresponds to a
value stored in one memory location ; each pixel corresponds to a binary digit in
an eight-digit binary number. This can be represented by a decimal number
between 0 and 255 . In the store there is a table of characters. For any given
character the PRINT command either finds the eight VALUEs from the table or
calculates them, and copies them into the appropriate display-me memory loca-
tions . This has the effect of drawing the character on the screen.

The Standard Character Set

The table of data for the standard character set is stored in ROM, the permanent
Read Only Memory of the computer. There are eight pieces of data for each of
the 96 characters, thus the table consists of 768 (96*8) consecutive locations
starting at 15616 . Each character has a unique CODE number, see page 183 of
the Spectrum BASIC Handbook (Vickers, 1982). The table contains the data for
each of the characters in turn, starting with space (CODE 32) and ending with the
copyright symbol (CODE 127) . When the PRINT command requires the eight
pieces of data for a given character , it looks at the system variable CHARS (see
page 173 of the Spectrum BASIC Handbook (Vickers, 1982)) , which contains
the address of a location 256 (eight times the CODE for space) less than the start
of the character table . In order to find the address of the first of the eight pieces
of data it multiplies the CODE number of the character by eight and adds it to
84 Advanced Graphics with the Sinclair ZX Spectrum

CHARS. Finally PRINT copies the data to the display file and the character
appears on the screen.
Run the following program, which is based on listing 1.2. It demonstrates how
this process works by showing what calculations are performed. A detailed ex-
planation of how to work out the display-file locations for any character block is
given in chapter 13, but for the moment we shall continue to use block (0 ,0)
only . Figure 5.1 is an example run of this program using 'T as INPUT data.

Listing 5.1
10 CLS: INPUT "Which character";AS: IF AS ="" THEN GO TO 10
20 LET AS = AS(1): PRINT AT 2,0;""""iASi'''''' SELECTED. CODE ("iASi") = "iCODE AS
30 PRINT AT 4,0;"CALCULATION OF DATA LOCATION"
~ LET CHARS = PEEK 23606 + 256*PEEK 23607
50 PRINT AT 6,2i"CHARS POINTS TO "iCHARS
60 LET TABLE = CODE AS*8
70 PRINT AT 7,3;"CODE AS * 8 = ";TABLE
80 LET START = CHARS + TABLE
90 PRINT AT 8,17i"-------": PRINT AT 9,2i" DATA STARTS AT "iSTART
100 LET CORNER = 16384: PRINT AT 11 ,0;"TABLE LOC. VALUE SCREEN LOC."
110 FOR I = 0 TO 7
120 LET VALUE = PEEK (START + I): LET MEMORY = CORNER + 256*1
130 PRINT AT I + 13,2iSTART + I: PRINT AT I + 13,22;MEMORY
1~ PRINT AT I + 13,13iVALUE
150 POKE MEMORY, VALUE
160 NEXT I
170 INPUT "ANOTHER GO ? "iYS: IF YS = "n" THEN STOP
180 GO TO 10

?
•• ? .. SELECTED. CODE €?) = 63
CALCULATION OF DATA LOCAT ION
CHARS POINTS TO 15360
CODE AS .. a = 504
DATA STARTS AT 15864
TABLE LOC. VALUE SCREEN LOC.
15864- o 16384-
15865 60 1664-0
15866 66 16896
15867 4 17152
15868 8 174-08
15869 o 17664-
15870 8 17920
15871 o 18176
Figure 5.1

Exercise 5.1
Rewrite listing 5.1 so that it will allow you to decide whether or not to accept
each data VALUE before it is POKEd into the display flle. If one of the eight
Character Graphics on the ZX Spectrum 85

VALUEs is rejected, INPUT a replacement for this VALUE. Experiment by


changing one or two VALUEs in a character.

The Graphics Mode

The address stored in CHARS is where you might expect to find data for the
character with CODE 0; however , characters with CODEs between 0 and 31 are
either control characters or unused . Since control characters are not displayed,
then no data are stored for them. Although CHARS points to this address, the
256 (32*8) bytes following it are not used and so are available for other purposes.
Furthermore, if a graphics mode character is selected for listing 5.1, then either
blank or totally spurious data are gathered. This is because the standard table
has data for CODEs 32 to 127 only and the graphics mode characters have
CODEs greater than 127; so the program is looking in the wrong place, beyond
the end of the table of data! The table in ROM immediately precedes the start
of RAM, the Random Access Memory used for temporary storage, so the pro-
gram will be looking at the display me that occupies the first 6K of RAM.

Block Graphics

The data for the block graphic set are not stored in ROM but instead are
calculated from the CODE of the character . Each block graphics character has
four quarters that are each represented, as on or off, by one of the last four
binary digits of the CODE number. In a block graphics character the first four
lines of eight pixels are identical, and the same is true of the bottom four lines.
.10001.1.01. = CODE ( ...... )
1.000X X X X = 8LOCK GRAPHICS
CHARACTE~: •

XXXX 1. 1. 0 1 =
>:----
FOUR CORNERS
''''HARACTER
OF
.- -- - -- -- -- ---- < <, --------: -- •
1111 1111 0000 1111
00001111 = VALUE FOR TOP 4 LINES
11111111 = VALUE 80TTOM 4 L J:NE :S
00001111
00001111
00001111
00001111
11111111 =
11111111
1111111.1
11111111
Figure 5.2
86 Advanced Graphics with the Sinclair ZX Spectrum

Provided we know that a character is a block graphic, we can generate two pieces
of data and use each four times to create the block. An example of how this is
achieved is shown in figure 5.2.
The block graphics set can be used to give medium -resolution graphics of 64
by 44 quarter blocks. Using this idea we can build up quite complicated two-
colour pictures very rapidly. The picture below (figure 5.3) was produced by the
program given in listing 5.2. The program draws a small set of concentric circles
in the top corner of the screen, then calls the 'big pixels' routine. This routine
asks us to specify a character block that will be the top-left corner for our start
position. From this position, for five character blocks down and for eight across,
it stores the data from the display file in the array S. For each pair of lines down,
it takes the eight pieces of data across and converts them to BINary strings (see
line 1130 onwards). These strings are used to build up the BINary representation
of the CODE for a graphics character by taking a two-bit section from each string
in turn and prefacing it by the CODE for graphics character (line 1230).

Listing 5.2
10~ REM main program
110 LET big pi xels = 100~
120 FOR 1=1 TO 18 STEP 3: CIRCLE 32,156,1: NEXT I
130 GO SUB big pi xels
140 STOP

10~~ REM big p i xels


1010 DIM PCB): DIM SC40,8)
1020 FOR 1=1 TO 8: READ PO): NEXT I: DATA 128,64,32,16,8,4,2,1
1030 DEF FN SCR,Cl = 16384 + INT CR/8 )*2048 + CR - INT CR/8)*8)*32 + C
1040 INPUT "TOP LEFT CORNER BLOCK IS AT ROW,COL ";ROW; " , ";COL
1049 REM store d isplay file data in array S f or 5*8 bloc ks f r om ROW,COL.
1050 FOR I = 0 TO 4
1060 FOR J = 0 TO 7
1070 LET P = FN SCROW + I,COL)
1080 FOR K = 0 TO 7
1090 LET SCI*8 + J + 1,K + 1) = PEEKCP + 256*J + K)
11~~ NEXT K: NEXT J: NEXT I
1109 REM set screen to 20*32 which is four t imes area to be expanded.
1110 BORDER 1: PAPER 7: INK ~: CLS
1120 PRINT AT 21,0; PAPER 1;,,: PRINT AT 0,0; PAPER 1;"
1129 REM take two lines of pixeLs at a time for transLation to quarter bLocks.
1130 FOR I = 1 TO 39 STEP 2
1140 LET A = I: LET B = I + 1
11 50 FO R J = 1 TO 8
1160 LET AS = "00~00000": LET BS = AS
1170 LET T = SCA,J): LET U = SCB,J)
1179 REM caLculate binary forms of pixels for J'th block across.
1180 FOR K = 1 TO 8
1190 IF T >= PCK) THEN LET T = T - PCK): LET ASCK) = "1"
120~ IF U >= PCK) THEN LET U = U - PCK): LET BSCK) = "1 "
1210 NEXT K
1219 REM take two pixels from each of the pair of bytes to make four quarters.
1220 FOR K = 1 TO 4: LET 0 = 2*K: LET C = 0 - 1
1230 LET CS = "BIN 10~0" + BSCC TO D) + ASCC TO D)
1239 REM convert binary form of quarter bLocks to character.
1240 LET C = VAL CS: PRINT CHR$ C;
1250 NEXT K: NEXT J: NEXT I
1260 RETURN
Character Graphics on the ZX Spectrum 87

... •• .
•....:..--. ~
••

I .' I· ••-

0))
I

II.l(.r-__
I
I
11··_·-.- II I

--••-. .-.-.
I. I .1

• ••
Figure 5.3

The graphics characters generated by the above program are printed on the
screen and form an exact image of whatever was in the 5 by 8 rectangle of blocks
specified. This image has been scaled in each direction by a factor of 4, so that it
now covers 20 by 32 blocks and each original pixel is represented by a square of
4 by 4 pixels .
With the COPY facility and the ZX printer listings, four times the normal
width and depth can be produced by using the 'big pixels' routine 16 times and
then joining together the separate pieces of listing.

Exercise 5.2
Write a routine that produces a listing of itself by COPYing each 5 by 8 section
as 'big pixels' to the printer.

User-defmed Graphics

The third set of characters is the User-defined Graphics set (CODEs 144 to 164) .
Another table of data for this set is held in the last 168 locations at the end of
memory. When the machine is turned on, the 21 characters from "A" to "U" are
copied into this table. These characters are accessed from the keyboard in graphics
mode by typing the letters "A" to "U". The data in the table for these characters
can be changed by the user , so that any required character can be displayed
directly from the keyboard . There is a built-in function USR, which when given
a string argument ("A" to "U"), will give us the address of the first piece of data
for the equivalent graphics character. The address of the start of this table is
stored in the system variable UDG (see page 175 of the Spectrum BASIC Hand-
book (Vickers, 1982)). The CODE of the graphics character minus 144 and
multiplied by 8 gives the relative position of the first of the eight pieces of data
for that character in the table . The USR function calculates this position and
adds it to UDG to get the absolute start address of the character in the store.
88 Advanced Graphics with the Sinclair ZX Spectrum

UDG can be altered so that fewer characters are available, say only those from A
to H, leaving more room for programs, although this is usually unnecessary unless
you have only 16K of RAM available. To illustrate the use of this function to
alter a graphics character, type in the following command

POKE USR "A",BIN 00100100

Now if we enter graphics mode and type "A", we see that two extra pixel
dots have appeared above the character "A". The program in listing 5.3 allows
you to redefine all eight BINary VALUEs that represent a graphics character.
The program then simulates graphics mode , allowing you to type user-defmed
graphics characters on the screen.

Listing 5.3
10 INPUT "CHARACTER TO BE REDEFINED",US: IF US="" THEN GO TO 10
20 IF US < "A" OR us > "U" THEN GO TO 10
30 LET MEMORY = USR us: CLS
4~ FOR I = 0 TO 7
5~ INPUT ("VALUE" + STRS I +" = BIN ");LINE BS
60 LET VALUE = VAL ("BIN" + BS)
70 POKE MEMORY + I,VALUE
80 IF LEN BS < 8 THEN LET BS = "0" + as: GO TO 80
90 PRINT as: NEXT I
10rJ PRINT AT 10,0;"TYPE CHARACTERS OR ENTER"
110 REM simulate graphics mode for letters A to U.
110 LET R = 12: LET C = 0
120 PRINT AT R, C; FLASH 1; "G"
130 IF INKEYS 0 "" THEN GO TO 130
1~ LET AS = INKEYS: IF AS = "" THEN GO TO 140
149 REM if 'enter' is pressed restart program.
150 IF AS = CHRS 13 THEN GO TO 10
160 IF AS < "a" OR AS > "u" THEN GO TO 130
169 REM convert character to equivalent user-defined graphic and print.
170 LET AS = CHRS (CODE AS + 47)
18111 PRINT AT R,C;AS
189 REM move fake cursor poi nters.
190 LET C = C + 1: IF C = 32 THEN LET C = 0: LET R = R + 1
: IF R = 22 THEN LET R = 12
20rJ PRINT AT R,C; FLASH 1;"G"
210 GO TO 130

Exercise 5.3
Use listing 5.3 to generate a graphics character consisting of a chequer-board
pattern of pixels instead of completely filled areas. Experiment with this using
various PAPER and INK colours in order to make new colours , for example, red
and yellow give orange.

User-defined graphics characters can be directly incorporated in your programs


to enhance the speed of display construction. The equivalent character could be
constructed by a series of DRAW and PLOT commands but this would take
longer in most cases. For instance, with characters we can build up patterns on
Character Graphics on the ZX Spectrum 89

the screen very quickly compared to the length of time it would take to PLOT
or DRAW the same pattern. Listing 5.4 shows how this can be done using user-
defined characters "A" to "D" (the darker characters on the listing denote
characters in graphics mode). When these graphics characters have been defined
then they, rather than the corresponding alphabetic graphics character, will
appear in program listings.

Listing 5.4
20~ REM main program
209 REM fill screen with a diagonal pattern of first four graphics characters.
21~ OVER 0
220 INPUT" INK ";1: INK I
230 INPUT " PAPER "; I: PAPER I
240 LET A$ = "ABCD": LET B$ = "BCDA"
250 LET C$ = "c DAB " : LET 0$ = "DABC"
260 FOR J = 0 TO 7
270 FOR I = 0 TO 4
280 PRINT AT I*4,J*4;A$
290 PRINT AT 1*4 + 1,J*4;B$
30~ PRINT AT 1*4 + 2,J*4;C$
31~ PRINT AT 1*4 + 3,J*4;D$
320 NEXT I
330 PRINT AT I*4,J*4;A$
340 PRINT AT 1*4 + 1,J*4;B$
350 NEXT J
360 STOP

Alternate Character Sets

So far we have used up to 37 graphics characters to create pictures, but by using


alternate standard sets we can add a further 96 with every new set we define. To
use an alternate set we simply change the value stored in CHARS so that it points
to our new set in RAM instead of the normal table. Wehave seen that the amount
of work that goes into constructing even one character is enough to imply that the
construction of a complete new character set will be a very arduous task. So we
need a program that will simplify this task, and also allow characters to be
altered once created. Listing 5.5 is such a character-generation and editing pro-
gram, and was designed for use in the development of graphical display programs.

Listing 5.5

1 CLEAR 62294: INK 0: PAPER 7: BORDER 7: OVER 1: LET N = 0


REM for 16K machines use CLEAR 255 + the value of S(I), where I is the index
of thelowest character set which will fit in the available store.
2 DIM Z$(8,8): DIM T$(8,8) : DIM S(6): DIM P(8): DIM B(8): DIM G(7)
REM line numbers to GO TO for menu options.
3 FOR I = 1 TO 7: READ G(I): NEXT I
: DATA 61,67,71,10~,HI6,112,119
REM powers of 2 ready for use in binary conversions.
4 FOR I = 1 TO 8: READ P(I): NEXT I
: DATA 128,64,32,16,8,4,2,1
90 Advanced Graphics with the Sinclair ZX Spectrum

REM values whfch must be placed in CHARS to use each alternative set.
for 16K machines these numbers should be,
15360,29271,30~39,30807,31575,32080 (see Appendix).
5 FOR 1=1 TO 6: READ SCI): NEXT I
: DATA 15360,62039,62807,63575,64343,64848
6 LET S =1 : GO SUB 17
REM check set 1 is being used and print menu.
7 CLS : PRINT AT 2,2;"*** CHARACTER GENERATOR ***"
8 PRINT AT 5,6; PAPER 5;"1"; PAPER 7;" PRINT ALL SETS"
9 PRINT AT 7,6; PAPER 5; "2"; PAPER 7;" ••• PRINT ONE SET"
10 PRINT AT 9,6; PAPER 5;"3"; PAPER 7;" ••• EDIT CHARACTER"
11 PRINT AT 11,6; PAPER 5;"4"; PAPER 7;" COpy SET TO SET"
12 PRINT AT 13,6; PAPER 5;"5"; PAPER 7;" SAVE SET"
13 PRINT AT 15,6; PAPER 5;"6"; PAPER 7;" LOAD SET"
14 PRINT AT 17,6; PAPER 5;"7"; PAPER 7;" RUN YOUR PROGRAM"
REM wait for valid option.
15 INPUT ''WHICH OPTION ";OP: IF OP < 1 OR OP > 7 THEN GO TO 15
REM jump to appropriate rout ine.
16 GO TO G(OP)
REM most subroutines are located at start of program for efficiency.
REM routine to change to set S by alter ing chars to point to new table of data.
17 LET HI = INT (S(S)/256): LET LO = S(S) - HI*256
18 POKE 23606,LO: POKE 23607,HI: RETURN
REM general routine to wait before clearing screen and returning to menu.
19 LET S = 1: GO SUB 17: INPUT "PRESS ENTER TO RETURN TO MENU"; LINE A$ RETURN
REM clear binary characters array .
20 FOR I = 1 TO 8: LET ZS(I) = " 0 ~ ~~0~~~" : NEXT I: RETURN
REM input a valid set number and give upper and lower bounds for characters.
21 INPUT "WHICH SET ";S : IF S < 1 OR S > 6 THEN GO TO 21
22 LET A = 32: LET B = 127: IF S = 6 THEN LET A = 65: LET B = 85
23 RETURN
REM input a valid character for chosen set.
24 INPUT "WHICH CHARACTER ";C$: LET C = CODE CS
: IF C < A OR C > B THEN GO TO 24
25 RETURN
REM draw eight by eight block grid at horizontal position altered by N.
26 LET NN =64 + N: FOR I = 0 TO 8
27 PLOT 1*8 + NN,64: DRAW 0,64
28 PLOT NN,I*8 + 64: DRAW 64,0
29 NEXT I: RETURN
REM produce graphical equivalent of binary string array ins ide grid.
30 FOR I = 1 TO 8: FOR J = 1 TO 8
31 LET P = 7: IF N = 0 AND Z$(I,J) = "1" OR N = 96 AND T$(I,J) = "1"
THEN LET P = 4
32 GO SUB 48: NEXT J: NEXT I: RETURN
REM overprint cursor on a square in the grid.
33 PLOT X,Y-2: DRAW 0,4
34 PLOT X-2,Y: DRAW 4,0
35 RETURN
REM double a corner of a character i nt o a temporary array T$ and save it.
36 INPUT "WHICH CORNER ";C: IF C < 1 OR C > 4 THEN GO TO 36
37 FOR I = 1 TO 8: LET rscn = "~~~~~~~~": NEXT I: GO TO 36 + C*2
38 FOR I = 1 TO 4: FOR J = 1 TO 4: IF Z$(I,J) = "1"
THEN LET TI = 2*1: LET TJ = 2*J: GO SUB 46
39 NEXT J: NEXT I: RETURN
40 FOR I = 1 TO 4: FOR J = 5 TO 8: IF Z$(I,J) = "1"
THEN LET TI = 2*1: LET TJ = 2*(J - 4) : GO SUB 46
41 NEXT J: NEXT I: RETURN
42 FOR I = 5 TO 8: FOR J = 1 TO 4: IF Z$(I,J) = "1"
THEN LET TI = 2*(1 - 4): LET TJ = 2*J: GO SUB 46
43 NEXT J: NEXT I: RETURN
Character Graphics on the ZX Spectrum 91
44 FOR I = 5 TO 8: FOR J = 5 TO 8 : IF Z$U ,J) = "1 "
THEN LET TI = 2*0 - 4): LET TJ = 2*(J - 4): GO SUB 46
45 NEXT J: NEXT I: RETURN
REM subrout ine to convert one pixel i nt o four pixels i n doubled array.
46 LET T$(TI,TJ) = "1": LET T$(TI-1,TJ) = "1 ": LET T$(TI,TJ-1) = "1"
: LET T$(TI-1,TJ-1) = "1": RETURN
REM overprint the identifying labels at the corners of the grid.
47 PRINT AT 5,7;"1 ": PRINT AT 5,16;"2": PRINT AT 14,7;"3"
: PRINT AT 14,16;"4" : RETURN
REM subroutine to print a coloured block in a square of the grid.
48 PRINT AT I+5,J+7+N/8; PAPER P;" ": RETURN
REM display doubled character in a grid on the right and save character.
49
LET N = 96: GO SUB 26: GO SUB 30
GO SUB 21 : GO SUB 24: L ET 0 = S(S) + C*8 - 1
50
FOR I = 1 TO 8: POKE 0 + I,VAL ("BIN" + UU»: NEXT I
51
52
LET N = 0: CLS: RETURN
REM copy ref l e ct i on of Z$ array about x-axis into T$ array.
53 FOR I = 1 TO 8: FOR J = 1 TO 8
54 LET T$(9-I,J) = Z$(I,J): NEXT J: NEXT I : GO SUB 59: RETURN
REM copy rotat ion of Z$ array into T$ array.
55 FOR I = 1 TO 8: FOR J = 1 TO 8
56 LET T$(9-J,I) = Z$(I,J): NEXT J: NEXT I: GO SUB 59: RETURN
REM copy reflect ion of Z$ array about y- axis into T$ array.
57 FOR I = 1 TO 8: FOR J = 1 TO 8
58 LET T$(I,9-J) = Z$(I,J) : NEXT J: NEXT I: GO SUB 59: RETURN
REM routine to copy T$ array back i nt o Z$ array.
59 FOR I = 1 TO 8: FOR J = 1 TO 8
60 LET Z$(I,J) = T$(I,J): NEXT J: NEXT I: RETURN
REM start of option hand l ing routines.
REM pri nt out all five complete character sets and user-defined graphics set.
61 CLS: FOR S = 1 TO 5: GO SUB 17
62 PRINT AT S*4 - 4,0;
63 FOR C = 32 TO 127: PRINT CHR$ C; : NEXT C
64 NEXT S: GO SUB 17: PRINT AT 20, 0;
65 FOR C = 65 TO 85 : PRINT CHR$ C;: NEXT C
REM use standard routine to wait then back to menu.
66 GO SUB 19: GO TO 7
REM print out one set and give the charcters with which they correspond.
67 CLS: GO SUB 21: LET SS = S
68 FOR C = A TO B: PRINT PAPER 6;CHR$ C;"=";: LET S = SS: GO SUB 17
69 PRINT CHR$ C;: LET S = 1: GO SUB 17: PRINT" ";: NEXT C
REM return to menu.
70 GO SUB 19: GO TO 7
REM option three, editting a character, clear screen and Z$ binary array.
71 CLS: GO SUB 20
REM which set and character, calculate data pos ition f or character.
72 GO SUB 21: GO SUB 24: LET 0 = S(S) + C*8 - 1
REM get ei ght bi nary numbers f rom table of data.
73 FOR 1=1 TO 8: LET BO) = PEEK (0 + 0: NEXT I
REM convert each number into a binary string of eight dig its.
74 FOR I = 1 TO 8: LET T = BO)
75 FOR J = 1 TO 8
76 IF T >= P(J) THEN LET Z$(I,J) = " 1" : LET T = T - P(J)
77 NEXT J: NEXT I
REM draw a gr id and put green blocks in squares to represent binary ones.
78 GO SUB 26: GO SUB 30
REM i nitialise cursor position i n pi xeLs and gr id reference values.
79 LET X = =
68: LET Y 124: LET 1= 1 : LET J = 1
REM overprint cursor on square.
80 GO SUB 33
92 Advanced Graphics with the Sinclair ZX Spectrum

RE~l wai t for next keypress.


81 IF INKEY$ <> .... THEN GO TO 81
82 IF INKEY$ = '''' THEN GO TO 82
REM get command and remove cursor.
83 LET A$ = INKEY$: BEEP 0.05,30: GO SUB 33
REM check for cursor movement controls with or without the shift key.
84 IF (A$ "5" OR A$ CHR$ 8) AND J > 1 THEN LET X = X - 8: LET J = J - 1
85 IF (A$ "6 " OR A$ CHR$ HI) AND 1 < 8 THEN LET Y = Y - 8: LET 1 = 1 + 1
86 IF (A$ "7" OR A$ CHR$ 11) AND 1 > 1 THEN LET Y = Y + 8: LET 1 = 1 - 1
87 IF (A$ "8" OR A$ CHR$ 9) AND J < 8 THEN LET X = X + 8: LET J = J + 1
RHI check for special commands, in upper or lower case.
REM Plot, fill in a square.
88 IF A$= "P " OR A$ = "p" TIiEN LET P 4: LET Z$(I,J) "1": GO SUB 48
RHI Off, blank out a square.
89 IF A$ = "0" OR A$ = "0" THEN LET P 7: LET Z$(I,J) " 0 " : GO SUB 48
REM Rotate character by 90 degrees anti-clockwise.
90 IF A$ = "R " OR A$ = "r " THEN GO SUB 55: GO SUB 311l: GO TO 79
REM reflect in the X or horizontal ax is.
91 IF A$ = "X" OR A$ = "x" THEN GO SUB 53: GO SUB 30: GO TO 79
REM reflect in the Y or vertical axis.
92 IF A$ = "Y" OR A$ = "y" THEN GO SUB 57: GO SUB 311l: GO TO 79
REM Merge another character with current pattern.
93 IF A$ = "M" OR A$ = "m" THEN GO SUB 26: GO 10 72
REM make Double-s ize co~y of one corner of character.
94 IF A$ = "D" OR A$ = "d" THEN GO SUB 47: GO SUB 36 : GO SUB 49: GO TO 78
REM unless yo u want to Save the character go back and wait for more commands.
95 IF A$ <> "s" AND A$ <> "s" THEN GO TO 80
REM replace character i n data table by using the BIN function to convert.
96 GO SUB 21: GO SUB 24
97 LET D= SeS) + C*8 - 1
98 FOR! = 1 TO 8: POKE D + I,VAL("BIN .. + Z$(I» : NEXT 1
REM return to menu.
99 GO SUB 19: GO TO 7
REM option four copy set to set.
111l11l INPUT "FROM SET "ts:" TO SET "iB
REM make sure sets are valid.
11111 IF A < 1 OR B < 1 OR A > 5 OR B > 5 THEN GO TO 111l11l
REM don't bother if sets are same.
=
11112 IF A B THEN GO TO 105
REM make copy of data from one table to another.
=
11113 PRINT AT 21,111li "PLEASE WAlT": FOR K 256 TO 111124
104 POKE (S(B) + K), PEEK (SeA) + K): NEXT K
REM return to menu.
105 GO SUB 19: GO TO 7
REM option five save data table for a set of characters as bytes on tape.
106 CLS: PRINT AT 2,6i"SAVING CHARACTERS": INPUT "WHAT FILE NAME "iN$
: IF N$ = .... THEN GO TO 7
107 PRINT AT 4,1I1liN$: INPUT "SAVE WHICH SET ''is
: IF (S < 2 OR S > 6) AND S <> 11 THEN GO TO 107
REM if you type 5+6 then spectrum sets S = 11 so save sets 5 and 6 together.
108 IF S = 11 THEN SAVE N$ CODE (S(5) + 256),168 + 768: GO TO 111
REM set 6 is smaller than normal sets.
=
11119 IF S 6 THEN SAVE N$ CODE eS(6) + 512),168: GO TO 111
1111l SAVE N$ CODE (S(S) + 256),768
REM return to menu.
111 GO SUB 19: GO TO 7
REM option six reload data table for a set of characters as bytes from tape.
112 CLS: PRINT AT 2,6i"LOADING CHARACTERS": INPUT "WHAT FILE NAME "iN$
: IF N$ = " .. THEN GO TO 7
113 PRINT AT 4,1I1liN$: INPUT "LOAD WHICH SET ''is
: IF (S < 2 OR S > 6) AND S <> 11 THEN GO TO 113
114 PRINT AT 21,1I1li"Start tape."
Character Graphics on the ZX Spectrum 93

=
REM i f you type 5+6 then spectrum sets S 11 so load sets 5 and 6 toge ther.
115 IF S = 11 THEN LOAD N$ CODE (S(5) + 256),168 + 768 : GO TO 118
REM load user defined set.
=
116 IF S 6 THEN LOAD N$.CODE (S(6) + 512),168 : GO TO 118
117 LOAD N$ CODE (S(S) + 256),768
REM return to menu.
118 GO SUB 19: GO TO 7

The CHARACTER GENERATOR routines are intended to take all the hard
work out of preparing and using defined characters : they allow you to edit and
manipulate characters, use alternate character sets and graphics characters, save
and reload defined chracters and immediately test your own programs. The
routines are designed for the 48K Spectrum to sit in the bottom part of the
memory (lines 1 to 118) , followed by your own program starting after line 118,
followed by the renumber and delete programs (from chapter 13) starting at line
9900 . If you have the 16K version, then this program should be run independ-
ently of other routines - see Appendix A.
The program first offers a choice of seven options, which we will look at in
turn.

(1) The first option is PRINT ALL SETS. This will print the normal character
set (set 1), followed by the four alternate character sets (2 to 5), followed by the
user-defined graphics set (set 6). The last few characters of set 5 will contain
.spurious data , a remnant of the GO SUE stack, which has been moved out of
harm's way.
(2) The second option is PRINT ONE SET. These are identified with the num-
bers 1 to 6 as follows: 1 standard set - cannot be changed; 2 to 5 alternate sets
- may temporarily replace standard set; 6 user-defined graphics set - always
available. On selecting one of these numbers the screen will display each character
of the standard set with = after it, both on a yellow background , followed by the
equivalent character of the alternate set. For set 6 this will be produced only for
the characters "A " to "U", and it will show the characters available when using
these keys in graphics mode .
(3) Option three is the editor. This is the most complicated option and has a
large set of commands accessed by typing their initial letter. First, though, you
will be asked with which set and which character you wish to start. If you want
to start with a blank grid of eight by eight pixels, use set 1 and the space charac-
ter . (To use the quote marks character it will be necessary to type it twice - see
page 47 of the Spectrum BASIC Handbook (Vickers, 1982)).
You will now be in edit mode and the character you have chosen will be
displayed as green blocks in an 8 by 8 grid. The cross in the top-left corner is the
edit cursor. The cursor is controlled by the standard cursor keys ("5" , "6", "7",
"8") either with or without the shift key.
The first two commands are PLOT or OFF, which change a square in the
character grid. Simply move the cursor over the square and press either "P" or
"0" .
94 Advanced Graphics with the Sinclair ZX Spectrum

"P" makes the square green, equivalent to a binary on or one INKed-in pixel,
and "0" erases the square to white.
The next three commands all specify transformations similar to those per-
formed on two-dimensional objects in chapter 4 . ROTATE turns the character
through 90 degrees anti-clockwise about its centre . X-AXIS reflects the character
about the horizontal axis and Y-AXIS reflects the character about the vertical .
These commands can be used to create text sets for any orientation.
Finally we have MERGE, SAVE and DOUBLE. MERGE allows any character
to be merged, into the grid, on top of what is already being edited. This is very
useful for creating foreign language sets ; for example, by placing a slash through
an 0 for Scandinavian languages, or by adding accents for French, etc . to letters.
The SAVE command asks in which set we wish to save the newly created charac-
ter , and to which standard character is it equivalent. If set 1 is specified the
character will be lost , since set 1 is held in the Read Only Memory of the
Spectrum: this can be useful to dispose of any unwanted grids created by mis-
take. DOUBLEis a powerful feature that allows you to take any quarter of the
character you are editing, create a double-size copy of the quarter and SAVE it
immediately as a single character . This option does not affect the character you
are editing, so all four corners may be copied in succession into four different
characters within the same editing stage. This feature can be used to create
characters of double, quadruple or larger size with ease.
(4) COpy SET TO SET is the fourth option available and can be used to make
copies of a complete set for subsequent manipulation, or simply to move one of
the alternate sets around in memory . Sets 2 to 5 are stored at the end of memory,
in the locations preceding the user-defined graphics, with set 5 ending at the
location immediately before the user-defined set. The area of store used for sets
2 to 5 is reserved and protected from BASIC use by the command CLEAR 62294
in the 48K version (see page 168 of the Spectrum BASIC Handbook (Vickers,
1982)).62294 is one less than the first location in the table for set 2. In order to
protect only the areas for sets I onwards, we need to evaluate S(I) + 255 and
place this number in the CLEAR command at the start of the program. S(I) is the
value assigned to the system variable CHARS that enables PRINT to use set I.
These values are READ from the DATA statement at line 3 . Note the changes
for the 16K machine given in Appendix A.
(5) and (6) Option five allows character sets to be saved on tape and option six
for them to be reloaded. If, in reply to the question 'WHICH SET', we type a
number between 1 and 6, then that set is SAVEd or reLOADed . Should we type
5 + 6 then both sets 5 and 6 will be saved or loaded as a single unit.
To allow other programs to load and use alternate sets of characters, lines 112
to 117 should be copied from the 'CHARACTER GENERATOR' along with the
subroutine (at 17 and 18), which allows switching between sets. The array S and
its DATA from line 5 must also be included.
(7) The final option is RUN YOUR PROGRAM, which will transfer control to
the first line following the character generator or, if nothing is there, stop.
Character Graphics on the ZX Spectrum 95

In order to familiarise yourself with the 'CHARACTER GENERATOR'


follow the instructions laid out below .
MERGE listings 5.4 and 5.5 on the 48K Spectrum ; run them separately on
the 16K machine. Create a character like an ink-blot pattern and SAVE it as
character "A " in set 6. Edit the character : rotate it and SAVE it as character
"B" in set 6. Edit "A" in set 6 : use X·AXIS reflection on it and SAVE it as "C"
in set 6 . Edit " B" in set 6 : use Y·AXIS reflection on it and SAVE it as "D" in
set 6. Now use option 7 to RUN YOUR PROGRAM and see what pattern
emerges.

Exercise 5.4
Experiment with various possible symmetries of characters and patterns for
placement of characters on the screen. Alter the program so that it tries all the
possible combinations of INK and PAPER colours within two nested FOR. . .
NEXT loops.


Figure 5.4

Exercise 5.5
Now create characters for dominoes using the 'CHARACTER GENERATOR'
from listing 5.5. This enables construction of a display similar to figure 5.4.

Exercise 5.6
Write a routine that copies one set to another but uses some of the editor
routines from the 'CHARACTER GENERATOR' to perform transformations on
each character as it is copied. Figure 5.5 shows a listing produced with a set that
has been ROTATED.

Let us now consider a complete program that has been developed using the
'CHARACTER GENERATOR' and subsequently separated from the develop-
ment system to stand alone. The 'MASTER MIND' program (listing 5.6) is shown
in mid-game in figure 5.6 and we can see immediately that an alternate character
96 Advanced Graphics with the Sinclair ZX Sp ectrum

.-f U .J UJ II Il: I.D OJ OJ (TJ ~ • • H Z :r::: (S) •• ' 0. ([ 0.111 (( r-,


Il) 0 u ClUJ u f'-. . 0 ::> UJ 0: .-4.. .J 111 Z II (S)
OJ ClHZ: N.,. .... Q) ,1))...... OHI: -1)) ... (0...... 0
HZ: (I)~'u) ._ .. OHI: 0.-1))...... OHI: m-(O....... OHI:
(!l~' f'-.-
t') lL0 Il: H" .-4 "'0 to-.. a: 111 ([0 C) ....,H....... ZI1I
X I- H ... 0 II I- II 10.-4 '10 to- ...to-.-4 ....-4 (S)(S) ....-4 (S)10 ...-4 .-4 ru ...
.-f..-l(TJ
~ lLOIl: H".-4 "'0 (0 .. a:11I([0 0.....,1-4 ZILI
X I- H. . 0 II I- II .-4 ru (0 "'10 ~ ... I!) OJ ... .-41J) ... (0 ...~ ru ....-4
IJ) lLOIl: H".-4 1-0 IJ).. 0:111([0 IJ)....,H....... ZILI
X I- H .. 0 II I- II .-4 \I) I!) IJ) lSI ... IJ) ru lSI I!) (JI ...IJ) OJ «) lSI to- "10I!) II')
t~ IJ) ~1J)..t (.) ~ (') "10 ~ I)) ~ I))
I.D .J IJJ I- V)".-4 .. C) 0 IJ) =' m .-4 to-
r··· (..'.J ...') .. o.a::HZ'" II'" OJ ...OJ . ...: ** * UI:II
cra:ul-wa ~IJJZIJJa::a:l-oa:
I))
***:
11. a: H Z I- II I- \1) ..10·... 0. ([ 0.111 a: 1t) .... :.-4:
u a: 11. IJJ a: r··· · ~: ••• 0. a: H Z I- II .J .J IJ) IJJ I- IJ) :
(I'I 11. a: H Z I- a: I- to- ..IJ)... a. II a.1JJ0: II') . ...: ru:
ll.'I: Il.IJJ cr r··· ~: ••• a. Il:HZ'" 0 Z IJJ \1) IJJ 1-:
.-fQ Il.Il:HZI- a:1- (TJ '10 ·, a.1Ia.1JJ1l: IJ). ..: l''):
ll. 'I ll. IJJ a: r· · •. : IJJ 0 H I- U I: II Il:II (,) I- IJJ Il::

Figure 5.5

set was used. This character set was created by DOUBL(E)ing the required
letters and numerals of set I and storing the top-left and top-right corners in the
capital letters of set 5 and the bottom corners in the lower case letters of set
5. The two sizes of peg were stored in the user-defined graphics set, which is
independent of the main set; hence they are always available whether we are
using set 1 or set 5. The DOUBLE letters were edit ed to smooth out their edges
and the combined sets 5 + 6 were stored on cassette tape as 'rnasterset' ,

Listing 5 .6
1 CLEAR 62294: INK 0: PAPER 7: BORDER 7
REM rout ines to allow use of alternate sets
REM remembe r to ma ke alterat i ons f or 16K machines as in l isting 5.5.
2 DIM S(6)
5 FOR I = 1 TO 6: READ SCI): NEXT I
: DATA 15360, 62039, 62807, 63575, 64343, 64848
6 LET S = 1 : GO SUB 17
7 GO TO 200
17 LET HI = INT (S(S) /256): LET LO = S(S) - HI*256
18 POKE 23606,LO: POKE 23607,HI: RETURN
112 CLS: PRINT AT 2,6;"LOADING CHARACTERS": LET N$ = "masterset"
113 PRINT AT 4,10;N$: LET S = 5 + 6
114 PRINT AT 21,HI;"Start tape.": PRINT AT 5,0;
115 LOAD N$ CODE (S( 5) + 256),168 + 768
118 RETURN
198 REM l oad characters and i nit ialise scores
199 REM arrays to hold Guess, Target and a copy of ta rget for checking.
200 GO SUB 112: LET MYSCORE = 0: LET SCORE = 0: DIM G(5): DIM T(4): DIM X(4)
209 REM use routine to draw disp lay.
210 RANDOMIZE: GO SUB 480
219 REM set up target colours and go i nt o guess loop.
220 FOR I = 1 TO 4: LET T(I) = INT (RND*6) + 1: NEXT I: LET GO = 0
229 REM next guess, if you have had s i x the n you lose.
Character Graphics on the ZX Spectrum 97

230 LET GO = =
GO + 1 : IF GO 7 THEN GO TO 390
239 REM i np ut routine for gu ess.
24~ GO SUB 780
249 REM print guess on board (A is graphics A).
250 PAPER 7
260 PRINT AT 1 + GO*3,11; INK G(1);"A "; INK G(2);" A";
INK GO);" A"; INK G(4); " A"
269 REM check guess aga i nst temporary copy of tar get.
270 LET NB = 0: LET NW = 0: FOR I = 1 TO 4: LET X(I) = T(I): NEXT I
279 REM look for e xact matches first, if found then cross off both pegs.
280 FOR 1 = 1 TO 4: IF GO) = X(I) THEN LET X(I) = 0 : LET NB = NB + 1
: LET G(1) = 7
29~ NEXT 1
299 REM check for r ight colour wrong position.
300 FOR 1 = 1 TO 4: FOR J = 1 TO 4: IF G(I) = X(J) THEN LET NW NW + 1
: LET X(J) = 0: LET GO) = 7
310 NEXT J: NEXT 1
319 REM set up array x with appropriate numbers of black and white pegs.
320 FOR 1 = 1 TO NB: LET X(I) = 0: NEXT I : FOR 1 = NB + 1 TO NB + NW
329 REM pad out array with non-visible green pegs.
330 LET X(1) = 7 : NEXT 1: IF NB + NW < 4 THEN FOR 1 = NB + NW + 1 TO 4
: LET X(I) = 4: NEXT 1
339 REM disp lay marker pegs on bo ard.
3~ PAPER 4: PRINT AT GO*3 + 1,2; INK X(1);"B"; INK X(2); "B";
350 PRINT INK X(3);"B"; INK X(4);"B";
359 REM i f you got i t all right then y ou win.
360 IF NB = 4 THEN GO TO 4~0
369 REM add one to computers score and loop back for next guess.
370 LET MYSCORE = MYSCORE + 1: PRINT AT 10,26; PAPER 6; INK 0;MYSCORE
380 GO TO 230
389 REM if you lose computer gets 10 more po ints.
390 LET MYSCORE = MYSCORE + 10: GO TO 410
399 REM i f you win you get 10 point s.
4~0 LET SCORE = SCORE + 10
~9 REM build up string for display at bottom.
410 LET IS CHRS 17 + CHRS 7 + "TARGET WAS" + CHRS 16 + CHRS T(1) + "A "
42~ LET 1$ IS + CHR$ 16 + CHRS T(2) + " A
430 LET 1$ IS + CHR$ 16 + CHR$ T( 3) + " A
44~ LET 1$ 1$ + CHR$ 16 + CHR$ T(4) + "A" + CHR$ 16 + CHR$ 0
450 LET 1$ 1$ + CHRS 6 + " PRESS ENTER TO CONTINUE
459 REM show t ar get and wait fo r 'enter' before restarting game.
460 INPUT (I$); LINE B$
470 GO TO 21 ~
479 REM draw boa rd.
480 OVER 0 : BORDER 6: PAPER 7: CLS: INK 0
489 REM use alternate set to print MASTER MIND in double size.
4~ LET S = 5: GO SUB 17
500 PRI~T AT 0,0;" ABCDEFGHIJKL ABMNOPQR"
510 PRINT AT 1 ,0;" abcdefgh ij kl abmnopqr"
519 REM pri nt out double s ize numbers.
520 PRINT AT 4,7;"ST": PRINT AT 5,7;"st"
530 PRINT AT 7,7;"UV": PRINT AT 8,7;"uv"
54~ PRINT AT 10,7;"WX": PRI~T AT 11,7;"wx"
550 PRINT AT 13,7;"Yl" : PRINT AT 14,7;"yz"
560 PRINT AT 16,7;"[\": PRINT AT 17,7;"{1 "
570 PRIN T AT 19,7;"Jt": PRINT AT 20,7;"}-"
579 REM wipe of sides of board in yellow.
580 PAPER 4: FOR 1 3 TO 20: PRINT AT 1,1;" ": NEXT I
59~ PAPER 6: FOR 1 = 0 TO 21: PRINT AT 1,24;" " : NEXT
600 PAPER 7: FOR 1 = 4 TO 19 STEP 3
609 REM print holes for pegs.
610 PRIr.-T AT I,11;"A A A A": NEXT
98 Advanced Graphics with th e Sinclair ZX Spectrum

61 9 REM print credi t s on s ide.


62 0 LET S = 1 : GO SUB 17 : PAPER 2
630 LET G$ = " c B Y BRIAN J ONES AND IAN ANGELL 1 982
641il FOR I = 0 TO 8
65 0 PRINT AT 1 2 + 1, 24 ; PAPER 6 ; I NK 2; CHR$ 13 3;
PAPER 2 ; I NK 7 ; G$ ( I * 6 + 1 TO 1*6 + 6 ) ;
66 0 PRIN T INK 2; PAPER 6;C HR$ 13 8: NEXT I
669 REM se t up s co re d i sp Lays .
670 PAPER 6: PRIN T AT 2 ,26 ;"YOUR" : PRI NT AT 3,25; "S CORE"
68 0 PRIN T AT 5, 26;S CORE
690 PRI NT AT 7,26; "MY": PRINT AT 8,25; "SCORE"
70 0 PRI NT AT 1 0 , 26 ;M YSCORE
709 REM dr a w horizontaL Lines ac r oss boar d.
71 ~ FOR : = 2 TO 20 STEP 3 : LE T Y = 168 - 8* 1
720 PLOT 7 ,Y : DRAW 17 6 , 0 : PLOT 7 ,Y - 1 : ·D R A~I 17 6,0: NEXT I
72 9 REf" d r a w ve rtic al l i re s on boa r d .
730 PLOT 7 ,7 : DR AW 0 ,145 : PL OT 8 , 7 : DRAW 0,1 45
741il PLOT 183 ,7 : DRAW 0 ,145: PLOT 1 84,7: DRAW 0,145
75 0 PLOT 55, 7: DRAW 0,1 45: PL OT 56 ,7 : DRAW 0,145
76 0 PLOT 7 1 , 7 : DRAW 0,1 45: PL OT 72 ,7 : DRAW 0,145
77 0 RETL" RN
779 REM ge t f our pe gs f or a guess .
78 0 L ET NG = 1
789 REM use su bro ut i ne t o buil d d i sp l ay st r i fig fo r i nput prompt .
790 GO SUB 83 0 : INPUT ( I$) ; G( NG) : IF G(NG) < 1 OR G( NG) > 7 THEN GO TO 7 90
799 REf" ba ck s pa ce t o r en.ove La st peg .
800 IF GOJG) = 7 THEN LET NG = NG - 1 : GO TO 790
80 9 REM keep go i ng tilL a LL f our peg s a re i n a nd have been con f i rmed.
810 L ET NG = NG + 1 : IF NG < 6 THEN GO TO 7 'J,l
82 0 RETURN
82 9 REM make up str ing wit h co Lou r code s a nd ch ar a cter s i ns tea d of numbers.
830 LET I$ = CHR$ 17 + CH R$ 7 + " YOUR GUESS "
840 IF NG <= 1 THEN L ET NG = 1 : RETURN
850 FOR J = 1 TO NG - 1: L ET I $ = 1$ + CHRS 16 + CHR$ G( J ) + "A ". NEXT J
86 0 RETURN

MR5TER MIND
. YOU

• SCOR

HY
SCORE
4-

Figure 5.6
Character Graphics on the ZX Spectrum 99

The routines taken from the 'CHARACTER GENERATOR ' program have
been left with their original numbering so that they can be easily identified and
compared with the original. The display for the top part of the screen is built up
in easy stages from characters, colours and lines so that the role of each stage of
construction is straightforward and easily adjusted. The program uses also the
techniques of dynamic INPUT strings (which will be discussed in chapter 13) to
create the display for the lower part of the screen.

Exercise 5.7
Tidy up the 'MASTER MIND' program, giving it a structured appearance.
Increase its legibility with suitable variable names especially for routines. Adapt
the 'MASTER MIND' program to play against you . (Programs that do this have
occasionally been published in the past in computing magazines. Some are still
available; see Ahl , 1980 and Liffick, 1979).
Finally in this chapter, we give a simple illustration of how effective character
graphics can be in producing a high-quality display. The following short program
uses the 'chesspiece' characters from the cassette tape to display a chess board
(for example, figure 5.7 - also see cover) and to move pieces in response to
INPUTs. You can of course produce your own new chess set.

Listing 5.7
9 REM set up to use just sets 1 and 5 for 16K use CLEAR 31830: S5 = 31575.
10 CLEAR 64598: LET S5 = 64343: LET S1 = 15360
20 INPUT" LOAD CHARS? "iYS: IF YS = "y"
THEN LOAD "chesspiece" CODE S5 + 256,768

100 REM layout boa rd


110 INK 0: PAPER 0: 80RDER 0 : CLS
120 PAPER 6
129 REM print yellow strip around board.
130 FOR I = 1 TO 20: FOR J = 1 TO 2
140 PRINT AT 21 - I,J + 5i" ": PRINT AT I,J + 23i" "
150 PRINT AT J,1 + 5i" " : PRINT AT J + 18,26 - Ii " "
160 NEXT J: NEXT 1
169 REM print squa res of board.
170 LET C = 4
180 FOR I = 2 TO 8 STEP 2: FOR J = 2 TO 8 STEP 2
190 PAPER C: PRINT AT J + 1,1 + 6i" " : PRINT AT J + 2,1 + 6i" "
200 PRINT AT 19 - J,24 - Ii" ": PRINT AT 20 - J,24 - Ii " "
210 LET C = 7 - C: PAPER C
220 PRINT AT J + 1,24 - Ii" ": PRINT AT J + 2,24 - Ii" "
230 PRINT AT 19 - J,I + b ; " " : PRINT AT 20 - J,1 + 6i" "
240 NEXT J: LET C = 7 - C: NEXT 1
249 REM print letters and numbers around board.
250 PAPER 6
260 FOR I = 1 TO 8: PRINT AT 20,6 + 2*IiCHR$ (64 + I)
: PRINT AT 2*1 + 2,25i(9 - I): NEXT I
300 REM set out pieces
310 DIM 8(8,8)
319 REM white pieces have ten added to the number identifying type of piece.
320 FOR 1=1 TO 8: LET 8(2,1) = 6: LET 8(7,1) = 16 : NEXT I
330 FOR =
I = 1 TO 3: LET 8 ( 1,1) 4 - I: 8(1,1+5) = I
100 Advanced Graphics with the Sinclair ZX Spectrum

340 LET B(8,I) = 14 - I: LET B(8,I+5) = I + 10: NEXT I


350 FOR 1=4 TO 5: LET B(1,I) = 9 - I: LET B(8,I) = 19 - I: NEXT I
359 REM set pointers to r out i nes.
360 LET move = 1000: LET input = 1100: LET piece = 1200: LET fLash = 1300
: LET charset = 1400: LET List = 1500
369 REM draw headings for move dispLay.
370 PAPER 0: INK 7: PRINT AT 1,0;"WHITE": PRINT 1,27;"BLACK"
380 PLOT 0,159: DRAW 39,0: DRAW 0,-1: DRAW -39,0
390 PLOT 216,159: DRAW 39,0: DRAW 0,-1: DRAW -39,0
399 REM use transparent paper and then caLL rout ine to draw each piece.
41110 PAPER 8: FOR K = 1 TO 2: FOR J = 1 TO 8: LET I = K: GO SUB piece
: LET 1= 9 - K: GO SUB piece: NEXT J : NEXT K
51110 REM main program
509 REM a rray t o hoLd moves and set no of moves to one.
510 DIM N$(2,100,5): BORDER Ill: LET S = S1: GO SUB charset: LET N
519 REM get whites move, flash squares specified.
520 LET 1$ = "WHITE": GO SUB input: LET F = 1: GO SUB flash
529 REM aLLow move to be canceLLed and re-entered.
530 INPUT "ACCEPT? ";Y$: IF Y$ <> "Y" THEN LET F = 0: GO SUB flash: GO TO 520
539 REM move piece and dispLay move on s ide.
540 GO SUB move: LET N$(1,N) = M$ : GO SUB List
549 REM repeat above process for bLack s ide.
550 LET 1$ = "BLACK": GO SUB i nput : LET F = 1: GO SUB flash
560 INPUT "ACCEPT? ";Y$: IF Y$ <> "Y" THEN LET F = 0: GO SUB flash: GO TO 550
570 GO SUB move: LET N$(2,N) = M$: GO SUB List
579 REM next move.
580 LET · N = N + 1: GO TO 520
1000 REM move
1009 REM move spec ified pieces and copy the pieces onto the screen.
1010 LET B(I2,J2) = B(I1.J1): LET I = 12: LET J =J2 : GO SUB piece
1020 LET BCI1 ,J1) = Ill: LET I = 11: LET J =J1: GO SUB piece
1030 RETURN
1100 REM input
1109 REM i nput coord inates of move squa re and dest ination square.
1110 INPUT (1$ + "'S MOVE No. " + STR$ N + " "L; LINE M$;"-"; LINE T$
: IF M$ = "STOP" OR M$ = " STOP" THEN STOP
1120 IF LEN M$ <> 2 OR LEN T$ <> 2 THEN GO TO input
1130 LET J1 = CODE M$(1) - 64: LET 11 = 9 - (VAL M$(2»
: IF 11 < 1 OR 11 > 8 OR J1 < 1 OR J1 > 8 THEN GO TO i nput
1140 LET J2 = CODE T$(1) - 64: LET 12 = 9 - (VAL T$(2»
: IF 12 < 1 OR 12 > 8 OR J2 < 1 OR J2 > 8 THEN GO TO i nput
1150 LET M$ = M$ + "-" + T$: RETURN

1200 REM piece


1201 REM IN: I, J
1209 REM redraw the square at I,J from the vaLue stored i n the board array.
1210 LET S = S5: GO SUB charset: LET B = B(I,J): INK 0
: IF B > 10 THEN INK 7: LET B = B - 10
1220 LET B = 2*B : LET A$ = CHR$ (63 + B) + CHR$ (64 + B)
: LET B$ = CHR$ (95 + B) + CHR$ (96 + B)
1230 IF B = 0 THEN LET A$ =" ": LET B$ A$
1240 PRINT AT 1*2 + 1,J*2 + 6;A$: PRINT AT 1*2 + 2,J*2 + 6;B$
1250 LET S = S1: GO SUB charset: RETURN
1300 REM fl ash
1301 REM IN: F,I1,J1.I2,J2
1309 REM change the fLash attr ibute of two squares I1,J1 and I2,J2.
1310 FLASH F: OVER 1 : INK 8: PRINT AT 12*2 + 1,J2*2 + 6;"
: PRINT AT 12*2 + 2,J2*2 + 6; " "
1320 PRINT AT n*2 + 1,J1*2 + 6;" ": PRINT AT 11*2 + 2,J1*2 + 6;"
1330 FLASH 0: OVER 0 : RETURN
Character Graphics on the ZX Spectrum 101

1400 REM cha r se t


1401 REM IN: 5
1409 REM change CHAR5 to 5 to use alternate sets.
1410 LET HI = INT (5/256 ): LET LO = 5 - 256*HI
1420 POKE 23606,LO: POKE 23607,HI: RETURN

1500 REM l ist


1509 REM list last 16 moves of each side on screen.
1510 LET T = N: IF T < 16 THEN LET T = 16
1520 FOR 1 = T - 15 TO T: PRINT AT 1 - T + 18,0 ; INK 7;N$(1,D
1530 PRINT AT 1 - T + 18,27; INK 7;N$(2,I) : NEXT 1
1540 RETURN

Figure 5.7

Exercise 5.8
Adapt the program in listing 5.7 to check for illegal moves and add facilities for
castling and en passant captures. If you have a lot of timell to spare then add
routines to make the computer play against you (see Liffick, 1979).

In the next chapter we shall consider how character graphics and our know-
ledge of two-dimensional geometry may be combined to form data displays.

Complete Programs

I. Listing 5.1 . Data required: A$. A$ should be any non-graphics mode


character, try "X " or "x".
102 Advanced Graphics with the Sinclair ZX Spectrum

II. Listing 5.2 ('main program' and 'big pixels') . Data required: ROWand
COL where 0 ~ ROW ~ 16 and 0 ~ COL ~ 24 . Try (0,0) and (1, 1).
III. Listing 5.3. Data required: U$ and eight BINary numbers, each at most
eight bits long to redefine the graphics character specified by U$. Try "A"
and Ill, 111000 , 1010101 , 101, 11111001, 1001, 1111 , 10110;and "B",
"C" and "D", each with permutations of these eight numbers. Then press
keys "A" to "U" to display the equivalent graphics characters or press
ENTER to restart program.
IV. Listing 5.4: no data required. Program III must be used to create graphics
characters "A", "B", "c" and "D".
V. Listing 5.5: the CHARACTER GENERATOR. Read text for description
and example of use.
VI. Listing 5.6: requires 'masterset' from tape, or the generation of your own
character sets. To play MASTER MIND, type the number ("1" to "6")
corresponding to the colour of peg you wish to enter. Pressing "7" removes
last peg. When four pegs are in position, type " 1" to enter guess.
VII. Listing 5.7: requires 'chesspiece' from tape. Type coordinates of start and
destination squares of move. The coordinates of a square are given by a
capital letter ("A" to "H") followed by a number ("1" to "8"). Try "E2"
followed by "E4". To ACCEPTMOVE type "Y", to reject the move
type "N".
6 Diagrams and Data Graphs

More information is available to more people than ever before. Businessmen are
being overwhelmed by massive documents containing reams of statistics on every
subject from capital expenditure to market research. Sociologists bombard us
with figures on child development and the increasing percentage of octogenarians
in Bournemouth. Worst of all, computers are piling up printouts of dreary data
covering every topic from astrology to zoology. Obviously something must be
done! Computers have helped to create the problem and they can also help to
solve it. The data must be presented in a more digestible manner: as pie-charts,
histograms, scientific graphs or just plain diagrams. With the advent of desktop
computers the increasing sales of programs that produce these displays has made
this one of the major growth areas in computer graphics. In this chapter we shall
see how such diagrams can be constructed with ease, givenjust a few tools to
aid our draughtsmanship .

Cursors

Before us is a sheet of PAPER on which we shall place objects. We require some


method for accurately controlling the position of these objects . This is usually
achieved with a cursor, which may be externally controlled by a joystick or
other analogue input devices. We, however, will use the keyboard to control
movements . This may not be as convenient to use as a joystick, but it requires
no extra expenditure on peripherals, which would achieve only the same effect
anyway. The 'cursor' routine, listing 6.1 , produces a pair of crosswires that are
OVERlayed on the display using transparent INK (INK 8) . These crosswires can
specify the pixel at their intersection or the character block in which they cross.
The cursor is moved in anyone of eight directions by the keys around the "F"
(see figure 6.1). If you have a joystick or similar peripheral attached to your
computer, then alter the 'cursor' routine so that it receives information from
that rather than the keyboard.
Pressing "F" itself centres the cursor on the screen. When a key is held down
the speed of movement gradually increases: a cursor that always moves just one
pixel per key depression is tedious to use! To aid in positioning the cursor there
is a Lattice that is switched on and off by pressing "L". This is automatically
removed, if it is on, when you press ENTER to enter a point.
104 Advanced Graphics with the Sinclair ZX Spectrum

KEYBORRD CONTROL5
FOR 'cursor' HOVEHENT

'" E Ri T ?
+-D F ~

C V B
ttl J, ~

Figure 6.1

Listing 6.1
57fJfJ REM cur sor
57fJ1 REM IN: PX,PY
57fJ2 REM OUT: PX,PY,ROW,COL
57fJ9 REM the rext Line is onLy executed on the first caLL to cursor.
5710 LET PX = 128: LET PY = 88: LET cursor = 5720: LET grid = 590fJ
5719 REM s t a r t of main cursor rout ine.
5720 INK 8: LET A = 1: LET FLAG = 1: OVER 1
5729 REM wait for key boa r d to be cLear be f or e Looki ng for comma nds.
5730 IF INKEY$ 0 ... . THEN GO TO 573fJ
5740 PLOT PX,0: DRAW 0,1 75: PLOT 0,PY : DRAW 255,0
5750 LET A$ = INKEY$: IF A$ = "" THEN LET A = 1: GO TO 575(;1
5760 IF CODE A$ > 64 AND CODE A$ < 96 THEN LET A$ = CHR$ (CODE A$ + 32 )
5770 PLOT PX,0: DRAW 0,175: PLOT 0,PY : DRAW 255,0
5780 IF (A$ = " e" OR A$ = "d" OR A$ = "c") AND PX >= A THEN LET PX = PX - A
5790 IF (A$ = " c" OR A$ = "v" OR A$ = "b" ) AND PY >= A THEN LET PY = PY - A
580fJ IF (A$ = "e" OR A$ = "r " OR A$ = "t") AND PX <= 175-A THEN LET PY = PY + A
5810 IF (A$ = " t " OR A$ = "g" OR A$ = "b" ) AND PX <= 255-A THEN LET PX = PX + A
582(;1 IF A$ = "f" THEN LET PX = 128: LET PY = 88
5830 IF A$ = " L" THEN GO SUB gr id
584(;1 IF A$ 0 CHR$ 13 THEN LET A = A + 1: GO TO 57 /.0
5850 LET COL = INT (PX/8): LET ROW = INT «175-PY)/8)
5860 IF FLAG = -1 THEN GO SUB gri d
5870 INK 0: OVER 0
5880 RETURN

590fJ REM grid


5909 REM routine cha nge s flag to remember whether grid is showing on screen.
5910 FOR J = 0 TO 255 STEP 8: PLOT J,0: DRAW 0,175: IF J < 176
THEN PLOT 0,J: DRAW 255,0
5920 NEXT J: LET FLAG = -FLAG: PLOT 255,0: DRAW 0,175: DRAW -255,0
5930 RETURN

Exercise 6.1
Write a 'main program' that calls 'cursor' and then prints a coloured square on
the screen at the specified block. It should also print out the ROW/COLumn
position of the block. Change the 'cursor' routine so that the standard cursor
keys ("5", "6 ", "7" and "8") can be used to move our cursor in character biock
steps about the graphics area.
Diagrams and Data Graphs 105

Attributes

We can extend the idea from exercise 6.1 to produce routines that change the
attributes of a given block or group of blocks without affecting their contents in
the display file. Listing 6.2 shows two routines that do this for the PAPER and
INK colours of a specified set of blocks .

Listing 6.2
40rJrJ REM paper
4010 GO SUB cursor: INPUT "WHAT COLOUR ";P: INPUT "No. OF BLOCKS (ROW*COL) "
i Ri "*" i C
411120 FOR I = ROW TO ROW + R - 1: FOR J = COL TO COL + C - 1
4030 PRINT AT I,J; PAPER P; INK 8; OVER 1; " ": NEXT J: NEXT I
41l141l1 RETURN

410rJ REM ink


411 rJ GO SUB cu rsor: INPUT "WHAT COLOUR ";P: INPUT "No. OF BLOCKS (ROW*COL) "
i Ri "* t1 i C
4120 FOR I = ROW TO ROW + R - 1: FOR J=COL TO COL + C - 1
413rJ PRINT AT I,J; PAPER 8; INK P; OVER 1;" ": NEXT J: NEXT I
4140 RETURN

Exercise 6.2
Write a 'main program' that LISTs part of itself and then allows you to highlight
parts of the listing using different INK or PAPER colours. Write routines to be
placed at lines 4050 and 4150 , which alter the FLASH or BRIGHT attributes of
blocks. (Why will this mean adding FLASH 8 and BRIGHT 8 to the 'paper' and
'ink' routines?) . Combine all four routines into one named 'attribute'.

Points and Lines

Having achieved simple interactive control over the appearance of our diagram,
we must now fill in the details of the picture. This requires routines for PLOT·
ting pixel points on the screen and for DRAWing lines.We could use program

Listing 6.3
420rJ REM poi nt
4210 INPUT "PRESS ENTER FOR CURSOR"; LINE AS
4220 GO SUB cursor: INPUT "OVER ( 1 OR III ) " ; 0 : INPUT "COLOUR " ; C
4230 PLOT INK C; OVER O;PX,py
4240 RETURN

430fl REM Line


4310 INPUT "PRESS ENTER FOR CURSOR "; LINE AS
4320 GC SUB cursor: LET SX = PX: LET SY =
PY
4330 INPUT "PRESS ENTER FOR CURSOR"; LINE AS
4340 GO SUB cursor: INPUT "OVER ( 1 OR 0 ) " ; 0 : INPUT "COLOUR ";C
435111 PLOT PAPER 8; INK C; OVER O;SX,SY
4360 DRAW PAPER 8; INK C; OVER O;PX - SX,PY - SY
4370 RETURN
106 Advanced Graphics with the Sinclair ZX Spectrum

listing 1.8, but it would be boring to go over every pixel in a line. Instead we use
two routines 'point' , which PLOTs individual pixels, and 'line' , in which we
simply specify the two end points of a line before joining them up. These two
routines are shown in listing 6.3.

Exercise 6.3
Write a 'main program' that allows you to use 'point' and 'line' to sketch a
picture of your Spectrum. Incorporate 'circle 1'or 'circle2 ' from listing 2.10 in a
'circle' routine ; where necessary, parameters, the centre and radius, are added
using the 'cursor'. Adapt your program from exercise 1.3 for use as a routine to
draw an n-sided polygon using the 'cursor' to enter the points. Add an extra
option to the 'line' routine to allow DRAWing of curved lines and then construct
a diagram similar to figure 1.1 Oa (it will be easier to use eight points around the
edge rather than twelve).
If you have a graphics pad then you can copy rough sketches from the pad
into the machine using an adjusted version of 'line' and 'point'. You should then
write programs to tidy up these pictures; that is, straighten lines and smooth out
curves.

Save and Load

Having spent some time and effort drawing and colouring a pretty picture, we
might wish to SAVE it for future reference. Another essential requirement is to
be able to LOAD a picture drawn by another program, and then alter it. The
two routines 'save' and 'load ' that make this possible are shown in listing 6.4.

Listing 6.4

450rl REM save


4510 INPUT "NAME OF PICTURE? ";N$: IF N$ = .... THEN RETURN
4520 SAVE (N$)SCREEN$
4530 RETURN

460fJ REM Load


4610 INPUT "NAME OF PICTURE? ";N$: IF N$ = .... THEN RETURN
4620 LOAD (N$ )SCREEN$
4630 RETURN

Exercise 6.4
Run the program in listing 3.1 (or LOAD figure 3.1 if you have it stored) and
then change the display to green INK on black PAPER. Furthermore, there are
similar statements in both routines 'save' and ' load'. To save space , combine
'save' and 'load' into a single routine.
Diagrams and Data Graphs 107

Labels

Listings 6.1 to 6.4 form the basis of our diagram construction package, but as
yet we have not put any labels on the diagrams. This is achieved with the 'label'
routine, listing 6.5 . Note that in this routine we make references to routines not
yet written . This is a typical situation given the structured modular approach
adopted throughout this book. In practice this means that whenever we come up
against a problem that is too large to tackle immediately, we simply give it a
name and deal with it later. In 'label' we decide that character strings drawn
using symbols from set 5 will be printed vertically. For reasons explained later,
we also define a special prefix (7 :) that indicates that the string of characters for
a label is to be printed in narrow characters using a special routine 'thin'. We also
assume that there is a routine named 'set' that enables us to switch between
character sets.

Listing 6.5
5400 REM Labe L
5410 GO SUB cursor: INPUT "SET:STRING ";AS: IF AS = "" THEN GO TO 5410
5420 INPUT "COLOUR ";CS: INK VALe"0" + CS)
5430 IF AS( TO 2) = "1:" THEN PRINT AT ROW,COL;AS(3 TO ): GO TO 5510
5439 REM che ck for spec iaL set numbers, set 5 i s pri nted verticaLLy.
5440 IF A$( TO 2) <> "5:" THEN GO TO 5470
5450 LET S = 5: GO SUB set : LET A$= AS(3 TO )
5460 FOR I = 1 TO LEN A$~ PRINT AT ROW-H1,COL;A$(I): NEXT I: GO TO 5510
5469 REM se t 7 specifies that the thin routine shouLd be used for pr inting.
5470 IF A$( TO 2) <> "7:" THEN GO TO 5490
5480 LET A$ = A$(3 TO ): GO SUB thin : GO TO 5510
5489 REM check vaLid number is given.
5490 LET S = VAL A$(1): IF S > 6 OR S < 1 OR A$(2) <> ":" THEN GO TO 5510
5499 REM pri nt out st ri ng in appropri ate set.
5500 GO SUB set: PRINT AT ROW,COL;A$(3 TO )
5511'1 LET S = 1 : GO SUB set
5520 INK 0: RETURN

Data Graphs

In an attempt to tidy up some of the loose ends, we introduce a general purpose


'main program' and a 'query' routine in listing 6.6 . Inevitably this creates as
many new loose ends as it ties up, but it should help to give us an overall view of
the tasks left unsolved . We introduce identifiers (lower case) for routines , to be
written later that , among other things, will allow us to draw special types of
diagrams; for example, 'histo'grams, 'pie'-charts and 'graph's .
The section of listing 6.6 before the 'main program' is a cleaned-up version of
those parts of the CHARACTER GENERATOR from chapter 5 necessary for
using alternate character sets.
A program containing all the routines from listings 6.1 to 6.7 was used to draw
most of the diagrams in this book that were not directly produced by example
programs . It was used also for adding labels to many of the figures that were
produced by programs ; for example , figure 4.1.
108 Advanced Graphics with the Sinclair ZX Spectrum

Listing 6.6

8 REM f or 16K machines make changes as g i v en in Listing 5 . 5 .


9 REM set up t o use aLternate character set s.
10 CLEAR 62294
20 INK 0 : PAPER 7 : CLS: DI M S(6)
30 FOR 1=1 TO 6: READ SCI) : NEXT I : DATA 15360,6 20 3 9, 62 80 7,6 357 5
,64343,6 4848
40 LET se t = 50: LET S = 1 : GO SUB se t : GO TO 20 0
50 REM set /ch ange to se t S
60 LET HI = I NT ( S( S)/ 256) : LET LO = S( S) - HI* 256
70 PO KE 236 06, LO: PO KE 23607 , HI: RETU RN
80 REM char Load
90 IN PUT "WHAT FILE NAME ? "; N$: IF N$ = " " THEN RETU RN
100 INPUT "LOAD WHICH SET ? " is : IF (S<2 OR S>6) AND S<>11 THEN GO TO 80
110 INPUT "St ar t tape, t hen pr es s en te r ."; LINE X$
120 IF S = 11 THEN LOAD N$ CODE (S(5) + 2 56 ) , 7 6 8 + 168: RETURN
130 IF S = 6 THEN LOAD N$ CODE (S (S ) + 51 2 ) , 16 8 : RETURN
140 LOAD N$ CODE ( S(S) + 256) ,768: RETURN

20 0 REM mai n program


210 =
LET re sta rt = 280 : L ET qu er y 500
220 LET hist o = 1000: L ET pi e = 20 00 : L ET gra ph = 3000
230 LET pape r = 40 00 : L ET i nk = 4100: L ET point = 4200: L ET Li ne 4300
: L ET sav e = =
4500: L ET Load = 46 00 : LET numbe r 4700
240 LET cha r Load = 80 : L ET cr ea te = 5000: LET thin = 5200
250 LET LabeL = 5400: L ET cu r sor = 5700
260 LET 1$ = " DEFI NE CHARACTER S ? " : GO SUB que ry : IF YES THEN GO SUB crea te
27 0 CLS: LET I$ = "L OA D CH ARACTERS? ": GO SUB query : IF YES THEN GO SUB charLoad
: GO TO 270
280 LET I$ " L OAD PICTURE ? ": GO SU B query: IF YES THEN GO SUB loa d
290 L ET 1$ = " DRAW DI AGRAM? ": GO SUB qu ery: IF NOT YES THEN GO TO 36 0
30 0 L ET I $ = "H IST OGRAM, PI E-C HART OR GRAPH ? " : GO SU B q uer y
3 10 LET di agram = 0: IF A$ = "h" THEN LET di ag r am = hi st o
32 0 IF A$ = " p" THEN LET di agram = pi e
330 IF A$ = " 9" THEN LET di ag ram = g r aph
340 IF d i ag r am = 0 THEN GO TO 280
350 GO SUB di agr am
360 LET 1$ = "LABEL PICTURE ? " : GO SUB quer y : IF YES THEN GO SUB Label
: GO TO 360
370 LET 1$ = " COLOUR PAPER ? " : GO SUB qu ery: IF YES THEN GO SUB pap er
: GO TO 370
380 LET 1$ = "COLOUR IN K ": GO SUB quer y: IF YES THEN GO SUB ink
: GO TO 3 80
390 LET 1$ = "DRAW POINT ": GO SUB query: IF YES THEN GO SUB poi nt
: GO TO 390
400 LET 1$ = " DRAW LINE ? " : GO SUB query: IF YES THEN GO SUB Line
: GO TO 400
410 LET 1$ "END PICTURE ? " : GO SUB query: IF NOT YES THEN GO TO restart
420 LET 1$ = "SAVE PICTURE ? ": GO SUB query: IF YES THEN GO SUB save
430 STOP

500 REM quer y


501 REM I N 1$
502 REM OUT: A$,YES
510 LET YES = 0
520 INPUT (1$ ); LINE A$: I F A$ THEN RETURN
530 LET A$ = A$ (1 ) : IF CODE A$ < 96 THEN LET A$ CHR$ ( CODE A$ + 32)
540 LET YES = ( A$ = " y " )
550 RETURN
Diagrams and Data Graphs 109

Special Characters

To complete our preparations for the 'label' routine , we need to create a set of
ROTATED characters, which is placed in set 5 for use in writing vertical labels.
This is done in the routine 'create' (listing 6.7), which uses some of the techni-
ques from the CHARACTER GENERATOR to copy a rotated version of set I
into set 5.

Listing 6.7
50~~ REM create/character s
50~9 REM create chara cter s for histogram routine.
501~ DIM PCB): DIM 0(3): LET 0(1) = 15: LET 0(2) = 255: LET 0(3) = 240
5020 FOR I = 0 TO 6: FOR J = 0 TO 7
503~ LET P(1) = USR "A" + 1*8 + J: LET P(2) = USR "H" + 1*8 + J
5040 LET P(3) = USR "0" + 1*8 + J
5050 FOR K = 1 TO 3: POKE P(K),0: NEXT K
5060 IF J > I THEN FOR K = 1 TO 3: POKE P(K),O(K): NEXT K
507~ NEXT J: NEXT I
5078 REM copy set 1 to set 5 with a rotation to get sideways characters.
5079 REM for 16K machines Q = 31831.
5080 DIM B$(8,8) : LET T = 256: FOR I = 1 TO 8: LET T = T/2: LET P(I) = T
: NEXT I: LET P = 15616: LET Q = 64599
5090 FOR I = 32 TO 127: FOR J = 1 TO 8 : LET B$(J) = "~~~~~~~~": NEXT J
510~ FOR J = 1 TO 8 : LET T = PEEK P: FOR K = 1 TO 8
511 ~ IF T >= P(K) THEN LET T = T - P(K): LET B$(9-K,J) = "1"
5120 NEXT K: LET P = P + 1 : NEXT J
513~ FOR J = 1 TO 8 : POKE Q,VAL( "BIN " + B$(J»: LET Q = Q + 1: NEXT J
5140 PRINT AT 10,10i"ROTATING "i CHR$ I
5150 NEXT I: CLS
5160 RETURN
520~ REM thin
5201 REM IN : ROW,COL,A$
5209 REM pri nt every other cha ra ct e r i n Left haLf of bLocks.
5210 LET S = 4: GO SUB set: OVER 1: LET TC = COL
5220 FOR 1=1 TO LEN A$ STEP 2 : PRINT AT ROW,TCiA$(I): LET TC = TC + 1 : NEXT I
5229 REM pr int other characters in between in r ight half of bLocks.
5230 LET S = 3: GO SUB set: LET TC = COL
5240 FOR 1 =2 TO LEN A$ STEP 2 : PRINT AT ROW,TCiA$(I) : LET TC = TC + 1 : NEXT I
5250 LET S = 1 : GO SUB set: OVER 0
5260 RETURN

Before generating the rotated characters, the 'create' routine initially redefines
the user-defined graphics set as three sets of seven characters , see figure 6.2, that
allow either the left or right halves, or all of a character block, to be INKed in
from the bottom up . These characters may be used, by OVERprinting, to obtain
horizontal bars of varying thicknesses on the screen; but they are primarily for
use in the 'histo'gram routines that follow.
For the remainder of this chapter we shall discuss some common types of
data display . The vast number of variations on each of the major themes of
graphical display make it impractical to discuss all possibilities. We shall, there-
fore , consider in detail just a few examples from each of the three main types of
display : histograms, pie-charts and graphs. From these simple examples it should
110 Advanced Graphics with the Sinclair ZX Spectrum
USER-DEFINED GRAPHICS CHARACTERS

..
FOR USE UITH HISTOGRAMS

AI B. .... C. D. E. F_ G

n. t<- L- t1- N_

~ Pw f4 R. S. T_ U

Figure 6.2

be possible to construct variations on these routines to display data in any man-


ner required . Again note the changes for the 16K machine given in appendix A.

Histograms

Histograms (or bar-charts) can be constructed by our programs to any height in


pixels and in any colour, provided both the width of the bars and the separation
between them are at least half a character block . Since this is quite normal for
histograms anyway, we can formulate a method for calculating the spacing and
width of bars once we know how many there are. The first part of the 'histo'
routine (listing 6.8) draws the axes, labels the vertical and then asks how many
bars are required . The width of the bars (X), and the size of the GAPs between
the bars, are both calculated (in multiples of half blocks) by a method that
ensures that 1/2 < GAP < X. On receiving each data item, the routine uses the
full and half-width characters together with the user-defined characters (from
'create') to build up strings representing the scale height of the bar. These strings
are used to fill in any full or half-width character blocks assigned to that bar by
prefixing them with '5 :' and using 'bar' to print them vertically. Note that the
axes lie in the character block just outside the area containing the bar-chart to
ensure their independence from any colour changes made inside this area.
Figure 6.3, a diagram presenting the annual rainfall in Egham, was construct-
ed using 'histo ' (/typel) from listing 6.8 and then 'label' ed.

Exercise 6.5
As variations on the standard 'histo ' routine we can write replacement routines
that can be MERGEd as required . Write a routine that calculates the position for
pairs of bars, where the bars within a pair are separated by half a block, but pairs
are separated from neighbouring pairs by at least one block . Use this to construct
diagrams similar to figure 6.4.
An example of a replacement 'histo' routine is given in listing 6.9. In this
version of 'histo' (/type2) the calculation of the width of the bars is altered to
provide whole character block values for X and GAP. Two data values are
requested for each bar, specifying the MAXimum and MINimum height range of
Diagrams and Data Graphs 111

Listing 6.8

1000 REM histo/type1


1009 REM set pointer to subroutine which pr ints bars.
1010 LET bar = 1320
1019 REM find scaLe and draw axes.
1020 INPUT "RANGE OF VERTICAL ";YB;" TO ";YT
1030 IF YB >= YT THEN GO TO 1020
1040 LET YSCALE = 128/(YT - VB)
1050 PLOT 47,152: DRAW 0,-129: DRAW 201,0
1059 REM LabeL verticaL axis.
1060 LET YDIF = (YT - YB) / 4: LET TICK = YB
1070 FOR I = 1 TO 5 : LET TK = INT <T:CK + 0.5)
1080 LET Y = 32*1 - 8: PLOT 47,Y: DRAW -3,0: LET ROW = INT «176 - Y)/8)-1
1090 LET A$ = STU TK: IF LEN A$ > 3 THEN LET A$ = A$( TO 3)
: IF TK > 999 OR TK < -99 TH EN LET A$ = "***"
1100 LET COL = 1 : IF TK >= 0 THEN LET COL = COL + 1
1110 IF ABS TK < 10 THEN LET COL = COL + 1
1120 IF ABS TK < 100 THEN LET COL = COL + 1
1130 PRINT AT ROW,COL;A$: LET TICK = TICK + YDIF
1140 NEXT I
1149 REM find number of bars required and caLcuLate how they can fit in.
1150 INPUT "No. OF BARS ";NB
1160 LET X = INT (25/NB + 0.5)/2: LET GAP = INT (50/NB - 2*X)/2
1170 LET GP = (25 - NB*X - (NB - 1)*GAP)*2: LET GP = INT «GP + 1)/2)/2
1179 REM position coLumn pointer at f irst bar then repeat Loop for each bar.
1180 LET COL = 6 + GP: FOR I = 1 TO NB
119l.l LET 1$ = "DATA FOR BAR" + STR$ I + " " : INPUT (1$);D;" COLOUR ";C
: INK C: LET W = X
1199 REM vaLues beLow the horizontaL axis are treated as singLe pixeL height.
1200 IF D <= VB THEN LET D = 0: LET H = 1: GO TO 1220
1209 REM caLcuLate the number of whoLe bLocks of height for bar.
1210 LET D = D - VB: LET H = INT (D*YSCALE + 0.5)
1220 LET IH = INT (H/8): LET L$ = "": LET M$ ="": LET R$ - ""
1229 REM construct strings to height for Left, middle and right of bars.
1230 FOR J = 1 TO IH: LET L$ = L$ + CHR$ 133: LET M$ = M$ + CHR$ 143
: LET R$ = R$ + CHR$ 138
1239 REM f ind number of pixels of height for special character at top.
1240 NEXT J: LET RH = H - IH*8: IF RH = 0 THEN GO TO 1260
1249 REM add spe cial characters to tops of bars.
1250 LET L$ = L$ + CHR$ (151 - RH): LET M$ = M$ + CHR$ (158 - RH)
: LET R$ = R$ + CHR$ (165 -RH)
1259 REM i f column pointer i s on a half-block print right biased part of bar.
1260 IF COL = INT (COL) THEN GO TO 1280
1270 LET A$ = L$: GO SUB bar: LET W = W- 0.5: LET COL = COL + 0.5
1279 REM print as many whole block bars as needed.
1280 IF W >= 1 THEN LET A$ = M$: GO SUB bar: LET W = W-
: LET COL = COL + 1: GO TO 1280
1289 REM see if left biased half-width bar is needed.
1290 IF W > 0.1 THEN LET A$ = R$: GO SUB bar: LET COL = COL + 0.5
1299 REM move column pointer to next bar and re-do loop.
1300 LET COL = COL + GAP: NEXT I
1310 INK 0: RETURN
1320 REM bar
1321 REM IN COL,A$
1329 REM pri rot A$ verti cally from row 19 upwards i n COLumn.
1330 FOR K = 1 TO LEN A$: PRINT AT 19 - K, INT COL;A$(K): NEXT K
1340 RETURN
112 Advanced Graphics with the Sinclair ZX Spectrum

. AVERAGE MONTHLY
100
RAINFALL in °E GHAH
.
... 7 5

...
f 5 0 !

_ ;J t'".::;

'- '--

oJ F H R H J J R 5 -I t ~
H ont h S

Figure 6.3

ROYAL HOLLOWAY COLLEG


UNDERGRADUATE TOTALS 1981

3 0 0

100

1 st 2 n d 3,d
YERR AT C O L LEG -

Figure 6.4
Diagrams and Data Graphs 113

the bar. By simply OVERprinting the bars, charts like figure 6.5 , of the monthly
temperature variation in Egham, can be produced. In order to understand this
fully, as well as other programs in the book, it is a good idea to scatter PRINT
statements throughout the listings, so you can follow the logic of the algorithms
as they are executed. A very nice feature in BASIC is that you can add extra

Listing 6.9
10~~ REM h lsto/type2
10~9 REM set pointer to subroutine wh ich pri~ts bars.
1010 LET bar = 1320: DIM 0$(2,3): LET 0$(1) = "MAX": LET 0$(2) "MIN"
1019 REM find scaLe and draw axes.
1020 INPUT "RANGE OF VERTICAL "iYBi" TO "iYT
1030 IF YB >= YT TH EN GO TO 1020
1040 LET YSCALE = 128/(YT - VB)
1050 PLOT 47,152: DRAW 0,-129: DRAW 201,0
1059 REM LabeL verticaL axis.
1060 LET YDIF = (YT - YB)/4: LET TICK = YB
1070 FOR I = 1 TO 5: LET TK = INT (TICK + 0.5)
1080 LET Y = 32*1 - 8: PLOT 47,Y: DRAW -3,0: LET ROW = INT «176 - Y)/8)-1
1090 LET A$ = STR$ TK: IF LEN A$ > 3 THEN LET A$ = A$( TO 3)
: IF TK > 999 OR TK < -99 THEN LET A$ = "***"
110~ LET COL = 1 : IF TK >= 0 THEN LET COL = COL + 1
1110 IF AB S TK < 111l TH EN LET COL = COL + 1
1120 IF ABS TK < 111l~ THEN LET COL = COL + 1
1130 PRINT AT ROW,COLiA$: LET TICK = TICK + YDIF
1140 NEXT I
1149 REM f ind number of bars required and caLcuLate an integer width fo r them.
1150 INPUT "No. OF BARS "iNB: OVER 1
1160 LET GAP = INT (13/NB): LET X = INT «26 - GAP*NB)/NB)
117~ LET GP = (25 - NB*X - (NB - 1 )*GAP): LET GP = INT «GP + 1 )/2)
1179 REM position coLum n poi nter at first bar then repeat Loop for each bar.
11E0 LET COL = 6 + GP: FOR I = 1 TO NB
: INPUT ("COLOUR FOR BAR " + STR$ I + ": ")iC: INK C
1189 REM Loop to i r put maximum and minimum vaLues for bar.
1190 FOR 0 = 1 TO 2: LET 1$ = "DATP. " + 0$(0) + " FOR BAR" + STR$ I + " "
: INPUT O$)iD: LET W = X
120fl IF D <= VB THEN LET D = 0: LET H = 1: GO TO 1220
1209 REM cal cuLate the number of whoLe bLocks of height for ba r.
1210 LET D = D - VB: LET H = INT (D*YSCALE + 0.5)
1220 LET IH = It\T (HI 8): LET M$ = ""
1229 REM construct string to height for bar.
1230 FOR J = 1 TO IH: LET 1'$ = M$ + CHR$ 143
1239 REM add spEciaL character for remaining he ight.
1240 NEXT J: LET RH = H - IH*8: IF RH = 0 THEN GO TO 1260
1250 LET M$ = M$ + CH ,$ (158 - RH)
1259 REM start at same coLumn for both bars in pair.
1260 IF 0 = 1 THEN LET OCOL = COL
1 27~ IF 0 = 2 THEN LET COL = DCOL
1279 REM output requirEd number of whoLe bLobk width bars.
1280 IF W >= 1 THEN LET A$ = MS: GO SUB bar: LET W = W- 1
: LET COL = COL + 1: GO TO 1280
1290 LET COL = COL + GAP: NEXT 0: NEXT I
130~ INK 11l: OVER 0: RETURN

1320 REM tar


1321 REM IN COL, ~.$
1329 REM pr i r.t A$ verticaLLy from row 19 upwards in COLumn.
133fl FOR K = 1 TO LEN A$: PRINT AT 19 - K, INT COLiA$(K ): NEXT K
1340 RETURN
114 Advanced Graphics with the Sinclair ZX Spectrum

STOPs to a program, interrogate the variable values, and then CONTinue , with -
out affecting the status of the program. This is a very useful tool for debugging
a program, as well as an aid to understanding a listing .

MONTHLY TEMPERATURE
30
RANGE in EGHAH

..
IIII
u 20

II
1.-

I
(JIl

.'
10

III •I
c
.-
u 0

1 '0

oJ FHA H oJ oJ A SON l'


Honths

Figure 6.5

Exercise 6.6
Try using a different colour PAPER when OVERprinting the bars to produce
two-coloured bars. Be careful when using data values giving scale heights with
less than eight pixels difference!

Problems will occur when using two different colours for one bar (exercise
6.6). If the MAXimum and MINimum values both fall in the same character
block, then three colours , these two plus the background, will be required with-
in one block. We may check whether problems will occur by comparing the
number of character blocks in the string produced for the MINimum data with
that for the MAXimum data . If they are of equal length then the simplest way
of avoiding trouble is to truncate the MINimum string by removing the last
character. This will remove any problems with the colours on the display but
will be slightly inaccurate . This whole problem will be avoided if we make the
colour of the lower part of the bar the same as the background colour, thus
ensuring that the bar is accurately drawn with only two different colours in each
block .
There are many , many more variations possible ; for example , drawing bars
above and below a central line in order to display fluctuations in currency
exchange rates. The fundamental ideas we have introduced should enable you to
produce any histogram to your own specification .
Diagrams and Data Graphs 115

Pie-Charts

The pie-chart is a favourite with economists and biologists who delight in telling
us how big each slice of our capital expenditure cake is, or alternatively which
bacteria are eating it . The usual requirements of a pie-chart program are that it
should draw pies of variable radii , it must be possible to pull out slices of the pie
from the centre , and provision for filling in or cross-hatching these slices must be
made available. The 'pie'-chart routine given in listing 6.10 achieves the first two

Listing 6.10
2000 REM pie/ chart
2009 REM set pointers to routines.
2010 LET hatch = 2300: LET in = 2800
2019 REM aLL segments are i nput and totaLLed to ca LcuLat e anguLar scaLe.
2020 INPUT "No. OF SEGMENTS "iNB: INPUT "COLOUR " i C$ : LET C = VAL ("0" + C$)
: LET TOT = 0
2030 DIM D(NB): FOR I = 1 TO NB : INPUT ("DATA" + STR$ I + to: ")iDO)
: LET TOT = TOT + DO): NEXT I
2039 REM use cursor to specify centre of pie.
2040 INPUT "PRESS ENTER FOR CENTERING PIE"iLINE Y$
2050 GO SUB cursor: LET XC = PX: LET YC = PY
2060 INPUT "RADIUS <IN PIXELS) " iRAD
2070 LET ASCALE = 2*PI/TOT: LET A1 = PI/2
2079 REM any wedge may be puLLed out by moving the cursor away from the centre.
2080 FOR I = 1 TO NB
2090 INPUT "PRESS ENTER FOR CENTERING WEDGE"iLINE Y$
2100 LET PX = XC: LET PY = YC: GO SUB cur sor: LET ANG = ASCALE*D(I)
: LET A2 = A1 - ANG
2109 REM if wedge is to move out caLcuLate dispLacement aLong i t ' s bisector.
2110 IF PX = XC AND PY =YC THEN GO TO 2140
2120 LET A3 = A1 - ANG/2: LET DIST = SQR «PX - XC)*(PX - XC) +
(PY - YC)*(PY - YC»
2130 LET PX = INT (XC + DIST*COS A3 + 0.5): LET PY = INT (YC + DIST*SIN A3
+ 0.5)
2139 REM enquire whether hatching is required and what type.
2140 INPUT "HATCH (x,y,b,n) "iH$ : IF CODE H$ < 96
THEN LET H$ = CHR$ (CODE H$ + 32)
2149 REM i f hatching is wanted i nput gap size between Lines and offset.
2150 IF H$ <> "n" THEN INPUT "JUMP "iJUMP,"REM "iREM
2159 REM draw segment of pie.
2160 INK C: PLOT PX,PY: LET X1 = INT (RAD*COS A1 + 0.5)
: LET Y1 = INT (RAD*SIN A1 + 0.5): DRAW X1,Y1
2170 LET A2S = A2: LET ASTO = ANG: LET XA = PX + X1: LET YA = PY + Y1
2180 LET XB = INT (RAD*COS A2 + 0.5): LET YB = INT (RAD*SIN A2 + 0.5)
2190 FOR T = A1 TO A2 STEP -3/RAD
2200 LET X2 = INT (RAD*COS T + 0.5): LET Y2 = INT (RAD*SIN T + 0.5)
: DRAW X2 - X1,Y2 - Y1: LET X1 = X2: LET Y1 = Y2
2210 NEXT T: DRAW XB - X2, YB - Y2: LET X2 = XB: LET Y2 = YB
2220 DRAW -XB,-YB: IF H$ = "n " THEN GO TO 2250
2228 REM calL hatching routine if needed.
2229 REM if angLe is greater than half circle then do hatching in two parts.
2230 IF ASTO > PI THEN LET A2 = A1 - PI: LET XB = 2*PX - XA: LET YB = 2*PY -VA
: GO SUB hatch: LET XA = XB : LET YA = YB: LET A1 = A2: LET A2 = A2S
2240 LET XB = PX + X2: LET YB = PY + Y2: GO SUB hatch
2249 REM loop back for next segment.
2250 LET A1 = A2: NEXT I: RETURN
116 Advanced Graphics with the Sinclair ZX Spectrum

requirements by using the 'cursor' to centre the chart and INPUTting the
RADIUS in pixels. The individual data items are then INPUT and TOTalled,
and this total is used to establish an angular scale for the 'pie'-chart. Each slice is
centred with the 'cursor', with any displacement of the 'cursor' from the centre
of the 'pie' being treated as a distance along the bisector of the slice and not as
an absolute position. With each new section the 'cursor' reappears at the original
centre of the 'pie'. Figure 6.6 was generated using this routine . . .

o nership of
dwellings
in t.he U.K.
o ner-
occupied
Local
authority
Rented

Figure 6.6

Hatching

Hatching the area of a pie-slice involves the intersection of a line with the
boundaries of the slice. To make the calculations simpler we shall hatch using
lines only in the horizontal direction or only in the verical direction , or both.
Furthermore we hatch only 'pie's that subtend angles less than or equal to 1T
radians (180 degrees) at the centre . For obtuse angles the 'pie' is treated as two
pieces, the first subtending 1T radians at the centre . The 'pie' routine enquires
whether the hatching is to be horizontal (answer "x"), vertical (answer "y "),
both ways (answer "b") or neither (answer "n").
The pie sections we are considering are each bounded by two line segments
and a circular arc. We must find which part of a hatching line (if any) lies inside
this segment. Becausethe 'pie' does not subtend an angle greater than 1T radians
at its centre there are only four possibilities

(1) a line may miss the pie altogether


(2) it may intersect the arc at two points
Diagrams and Data Graphs 117

(3) it may intersect the arc and one of the line segments
(4) it may intersect both line segments

The special cases where the line coincidently cuts the arc and a line segment
at the same point may be included in one of the above four possibilities. The
explanation of the hatching algorithm is given with reference to horizontal
hatching; the vertical follows in an equivalent manner . We first find the MAXi-
mum and MINimum y-values of points within the 'pie' section. Then we consider
all horizontal hatching lines with equations of the form Y = hJUMP + REM
between these limits (0 ~ REM ~ JUMP - I) . For each hatching line we calcu-
late the two points of intersection with the extended line segments and then
check whether their MU values lie between 0 and I; that is, whether the inter-
section is between the centre of the circle and the arc. Next we find the two
points of intersection of the hatching line with the complete circle containing
the arc, and then check whether they lie on the arc. From these we can find the
two points of intersection of the pie section and the hatching line, and these are
then joined. This whole process is programmed in listing 6.11 and an example of
its use is given in figure 6.7 . Note that to fill in a slice completely we simply set
JUMP equal to 1.
Listing 6.11
2300 REM hat ch
2309 REM if cross hatching is required then run hatch rout ine twice.
2310 IF H$ ="b" THEN LET H$ = " x": GO SUB 2320: LET H$ = "y"
: GO SUB 2320: LET H$ ="b" : RETURN
2319 REM set hatch ing var iabLes to controL direct ion of Lines.
2320 IF H$ = "y" THEN LET PZ = PX: LET PT = PY : LET ZA = XA: LET TA = YA
: LET ZB = XB: LET TB = YB
2330 IF H$ = "x" THEN LET PZ = PY: LET PT = PX: LET ZA = VA: LET TA = XA
: LET ZB = YB: LET TB = XB
234l<l DIM Z(3)
2349 REM find max. and min. coordinates for Lines wh ich pass through segment.
2350 LET T = PI/2: LET MAX = 0 : LET MIN = 0
2360 LET VAL = SIN A1: IF H$ = "x" THEN LET VAL = COS A1
2370 IF MAX < VAL THEN LET MAX =VAL
2380 IF MIN> VAL THEN LET MIN =VAL
2390 IF T > A1 THEN LET T = T - PI/2: GO TO 2390
2400 IF T < A2 THEN GO TO 2450
2410 LET VAL = SIN T: IF H$ = "x" THEN LET VAL = COS T
2420 IF MAX < VAL THEN LET MAX = VAL
2430 IF MIN> VAL THEN LET MIN = VAL
2440 LET T = T - PI/2: GO TO 24l<l0
2450 LET VAL = SIN A2: IF H$ = "x" THEN LET VAL = COS A2
2460 IF MAX < VAL THEN LET MAX =VAL
2470 IF MIN> VAL THEN LET MIN = VAL
2480 LET NEWMIN = INT (INT (RAD*MIN + 1)/JUMP)*JUMP + REM
2489 REM fo r Lines which crosses segment find i ntersections with radii and arc.
2490 FOR E = NEWMIN TO MAX*RAD STEP JUMP
2499 REM store i ntersect ion coordinate informat ion in array Z(1:4).
2500 LET IC 0 =
2510 LET DENOM = TA - PT: IF DENOM = 0 THEN GO TO 2540
2520 LET MU = E/DENOM: IF MU < 0 OR MU > 1 THEN GO TO 2540
2530 LET IC = IC + 1: LET Z(Ie> = PZ + MU*<ZA - pZ)
2540 LET DENOM = TB - PT: IF DENOM = 0 THEN GO TO 2580
2550 LET MU =E/DENOM: IF MU < 0 OR MU > 1 THEN GO TO 2580
118 Advanced Graphics with the Sinclair ZX Spectrum

2560 LET IC = IC + 1: LET Z(IC) = PZ + MU*(ZB - PZ)


2569 REM if more than two points of intersection found, deLete dupLicates.
2570 IF IC = 2 AND Z(1) = Z(2) THEN LET IC = 1
2580 IF IC <> 2 THEN GO TO 2610
2589 draw hatch Lines.
2590 IF HS = "y" THEN PLOT Z(1),E + PT: DRAW Z(2) - Z(1),0: GO TO 2710
2600 IF HS = "x" THEN PLOT E + PT,z(1): DRAW 0,z(2) - Z(1): GO TO 2710
2610 LET DISC = RAD*RAD - E*E: IF DISC < 0 THEN GO TO 2710
2620 LET DISC = INT (SQR DISC + 0.5)
2630 LET ZZ = PZ + DISC: LET AZ = DISC: GO SUB in: IF OUT THEN GO TO 2650
26~ LET IC = IC + 1: LET Z(IC) = ZZ
2650 LET ZZ = PZ - DISC: LET AZ = -DISC: GO SUB in: IF OUT THEN GO TO 2670
2660 LET IC = IC + 1: LET Z(IC) = zz
2670 IF IC < 2 THEN GO TO 2710
2680 IF IC = 2 THEN GO TO 2590
2690 IF z(n = Z(2) THEN LET zcz: = Z(3)
2700 GO TO 2590
2710 NEXT E
2720 RETURN
2800 REM in
2808 REM caLcuLate angLe from centre to point of intersection.
2809 REM i f angLe Lies between angLes of ends of segment then point
of int er se ct i on i s on the arc of the segment.
2810 LET BZ = AZ: LET EZ = E
2820 IF HS = " x" THEN LET BZ = E: LET EZ = AZ
2830 IF BZ = 0 THEN LET PHI = -PI/2: IF EZ > 0 THEN LET PHI = -PHI
2840 IF BZ = 0 THEN GO TO 2860
2850 LET PHI = ATN (El/BZ): IF BZ < 0 THEN LET PHI = PHI - PI
2859 REM set flag t o i r.di ca t e whether or not point is vaLid.
2860 LET OUT = (PHI >= A1l OR (PHI <= A2)
2870 RETURN
An n e I. ids
J.

FREQUENCY Crustaceans
OF
INVERTEBRATES IN A BRITISH POND
Figure 6.7

Graphs

As our final example of graphical data presentation we must consider scientific


graphs of functions and graphs of discrete points. Such diagrams require co·
Diagrams and DataGraphs 119

ordinate axes that need not be fixed, and can cover a bewildering variety of
ranges for their scales. The method we use to decide on the placing of a particu-
lar axis is fairly standard: if zero should lie in the range of the graph then the axis
passes through that point, otherwise it lies on the edge of the graphics area,
closest to zero. Five TICKs are then placed along each axis and the scale value
at that point is written close to each TICK. The need for accuracy in scientific
graphs makes us wish to include as many characters as possible. As things stand
we can have only 32 characters across the screen and 22 up it, so this is where
'thin' comes in . We used the CHARACTER GENERATOR to create two sets of
thin characters that are half the width of normal characters : one set having
characters in the left half of the character block and the other set being in the
right half. When a string is to be printed as thin characters, the 'thin' routine
prints every other character of the string in the left-biased set and then OVER-
prints this, with the remaining characters in the right-biased set. This places two
thin characters in each block, giving us 64 print positions across the screen. The
numbers to be printed as 'thin' 'label 's still need to be converted into strings and
made consistent in length and/or decimal accuracy. This is achieved by the
routine 'number', which follows in listing 6.12 . Note that the routine 'thin' has
already been used in the 'label 'ling of figure 6.6.

Listing 6.12
300~ REM graph
30~9 REM symbol routine is used to mark data points on discrete graphs.
3010 LET symbol = 3500
3019 REM calculate scales and draw axes.
3020 INPUT "X GOES FROM "iXBi" TO "iXT: IF XT <= XB THEN GO TO 3020
3030 INPUT "Y GOES FROM "iYBi" TO ";YT: IF YT <= YB THEN GO TO 3030
304'!1 LET XSCALE = 1921(XT - XB) : LET YSCALE = 128/(YT - VB)
3050 LET XO = INT (-XB*XSCALE + 32.5): LET YO = INT (-YB*YSCALE + 24.5)
3059 REM if zero is not in range of graph move axis to appropriate edge.
3060 IF YT < 0 THEN LET YO = 153
3070 IF YB > 0 THEN LET YO = 23
3080 IF XT < 0 THEN LET XO = 224
3090 IF XB > 0 THEN LET XO = 31
3100 PLOT XO,23: DRAW 0, 128: PLOT 31,YO: DRAW 192, 0
3101 REM use th i n routine to print labe ls on axes with fou r figure accu racy.
3110 LET XDIF = (XT - XB)/4: LET YDIF = (YT - YB)/4
3120 LET X = XB: LET Y = VB: FOR J = 1 TO 5
3130 LET PX = INT «X - XB)*XSCALE + 32.5): LET PY = YO
3140 PLOT PX,PY-2: DRAW 0,4
3150 LET COL = INT (PX/8) - 1: LET ROW = INT «175 - PY)/8) + 1
3160 LET A = X: GO SUB number: GO SUB th in
3170 LET PY = INT «Y - YB)*YSCALE + 24.5): LET PX = XO
3180 PLOT PX-2,PY: DRAW 4,0
3190 LET COL = INT (PX/8) + 1: LET ROW = INT «175 - pn/8)
3200 LET A = Y: GO SUB number: GO SUB thin
3210 LET X = X + XDIF: LET Y = Y + YDIF: NEXT J
3220 INPUT "CONTINUOUS OR DISCRETE GRAPH "i D$: IF 0$ <> "c " AND 0$ <> "d"
THEN GO TO 3220
3230 IF 0$ = "d" THEN GO TO 3320
3239 REM i nput the function to be plot ted.
3240 INPUT " F(x) : y="; LINE F$
3250 LET X = XB : LET Y = VAL (F$) : LET OY = INT «Y-YB)*YSCALE + 24.5)
120 Advanced Graphics with the Sinclair ZX Spectrum

3260 PLO, 32,OY


3270 FOR I = 33 TO 224
3280 LET x = (I - 32)/XSCALE + XB
3290 LET Y = VAL (F$): LET IY = INT «Y-YB)*YSCALE + 24.5)
3300 DRAW 1,IY - OY: LET OY = IY: NEXT I
3310 RETURN
3319 REM discrete graph required so input set of points.
3320 INPUT "No. OF POINTS ";NP: DIM X(NP): DIM Y(NP)
3330 FOR I = 1 TO NP: INPUT ("X(" + STR$ I + ") ");X(I);
(" Y(" + STR$ I + ") ");Y(I): NEXT I
3339 REM sort points into ascending order of X coordinate.
33~ FOR I = 1 TO NP - 1: FOR J = I + 1 TO NP
3350 IF X(J) < X(I) THEN LET T = X(I): LET X(I) = X(J): LET X(J) = T
: LET T = Y(I): LET Y(I) = Y(J): LET Y(J) = T
3360 NEXT J: NEXT I
3370 LET X = INT «X(1) - XB)*XSCALE + 32.5)
: LET Y = INT «Y(1) - YB)*YSCALE + 24.5)
3380 PLOT X,Y: LET OX = X: LET OY = Y: GO SUB symbol: PLOT OX,OY
3389 REM join up points and pLace a 'symboL' at each point.
3390 FOR I = 2 TO NP
3~0 LET X = INT «X(!) - XB)*XSCALE + 32.5)
: LET Y = INT «Y(I) - YB)*YSCALE + 24.5)
3410 PLOT X - OX,Y - OY: LET OX = X: LET OY = Y: GO SUB symboL: PLOT OX,OY
3420 NEXT I: RETURN
3500 REM symbol
3510 DRAW 0,1: DRAW 1,0: DRAW 0,-2: DRAW -2,0: DRAW 0,2
3520 RETURN

4700 REM number


4710 LET A$ = STR$ A : IF LEN A$ <= 4 THEN RETURN
4720 LET A$ = A$( TO 4)
4730 RETURN

Exercise 6.7
Write an extended 'number' routine that allows you to specify the format of
the string to be returned. One way of doing this is to enter a string containing a
template for the number format; for example, the string '##.## #! could
specify a number with two digits before the decimal point and three decimal
places after it.

Exercise 6.8
Construct the thin 'sets' required for numerical labelling (these appear on the
cassette tape as 'thin3' and 'thin4'). Use them for 'label 'ling diagrams. Figure 6.8,
which was drawn using listing 5.2, will help you with your construction.

I) 1 2 3 .:I
6• ., 3 9
+ •-••
/.
Figure 6.8
Diagrams and Data Graphs 121

The choice is now offered between entering a functional representation of


points on a continuous curve, and entering a set of discrete data points to be
joined in a saw-tooth type pattern by straight lines. In the functional section of
the routine the height of the line above each pixel point on the X-axisis calcu-
lated and these points are joined by lines. In the discrete section the X-co-
ordinate and Y-coordinate of available data points are INPUT and sorted into
ascending order of the X-coordinate. These points are then joined by a line. One

Figure 6.9

CHANGES IN pH VALUE OF
RIVER YATER OVER 24 HIs .
•. Z 5 y - - - - r - - - - r - - - - - , -_ _---.

• .... dar&. dark

,.
> 7.75
I
Q
1.501

'.1"S +------4-----.J--.----+--_ _ ~
~ ~ 1.2tIt 1.-
TIHE (Hou,s)
Figure 6.10
122 Advanced Graphics with the SinclairZX Spectrum

example of each type of diagram is given. Figure 6.9 shows a typical continuous
cosine curve and figure 6.10 shows discrete scientific data about the pH levels of
a river.

Exercise 6.9
It can be seen that the only requirement for a graph of this type is a set of co-
ordinates in ascending order of X, which are then joined up. This set can be
created in any manner: by a series of READ statements or by a multi-line
calculation in a subroutine. Instead of eVALuating the function string F$ we
could write a routine that is used every time we need to calculate a point on the
curve. Produce a routine that allows the graph of SIN X/X to be drawn , avoiding
the calculation SIN 0/0 .

Complete Programs

We group listings 6.6 ('main program', 'charload' , 'set' and 'query'), 6.1 ('cursor'
and 'grid'), 6.4 ('save' and 'load') under the name 'libdiag', and use it with 6.2
('paper' and 'ink'), 6.3 ('point' and 'line'), 6.5 ('label') and 6.7 ('create' and
'thin'): all found on the tape. Note the changes for the 16K machine mentioned
in appendix A.

I. 'libdiag', 6.2, 6.3,6.5 ,6.7 . Data required :

'DEFINE CHARACTERS?' (type) Yes to create special rotated characters


and blocks for histograms; otherwise ~o
'LOAD CHARACTERS?' r if special character sets (including ones above)
are to be LOADed from tape; otherwise ~o
'LOAD PICTURE?' r LOAD previously stored picture ; otherwise ~
'DRAW DIAGRAM?' r to draw a histogram, pie-chart or graph ; ~ if
picture is to be edited only
'LABEL PICTURE?' r to use 'label'; otherwise ~
'COLOUR PAPER?' r or~ . If r then specify 'WHICH COLOUR' (for
example, 1: move cursor into position, using 'grid' if necessary) and type
size of area in blocks ROW*COL (for example, ~*i.)
'COLOUR INK?' If r then specify 'WHICH COLOUR' (for example ~:
move cursor into position , using 'grid' if necessary) and type size of area in
blocks ROW*COL (for example, l *.D
'DRAW POINT?' If r then use cursor to specify point: 'WHICH COLOUR'
(for example, §.) and OVER (lor Q)
'DRAW LINE?' Ifr then use cursor to specify end points: 'WHICH
COLOUR' (for example, §.) and OVER (lor Q)
'END PICTURE?' If~ then go through sequence again
'SAVE PICTURE?' If r then input name of picture
Diagrams and DataGraphs 123

Experiment with the data graphs.


II . 'libdiag' and listing 6 .8 ('histo'/typel). Data required: for example

'RANGE OF VERTICAL' 0 'TO' 100


'No . OF BARS' 6
'DATA FOR BAR l' 56
-
'COLOUR' -2
'DATA FOR BAR 2' 95
-
'COLOUR' -6
'DATA FOR BAR 3' 20 'COLOUR' 4
- -
'DATA FOR BAR 4' 77 'COLOUR' 5
- -
'DATA FOR BAR 5' 54'COLOUR'
- -
1
'DATA FOR BAR 6' 33 'COLOUR' 3

III. 'libdiag' and listing 6.9 ('histo'/type2). Data required: for example

'RANGE OF VERTICAL' 0 'TO' 50


'No . OF BARS' 4
'COLOUR FOR BAR l' 2
'DATA MAX FOR BAR l' 44
'DATA MIN FOR BAR l' 22
'COLOUR FOR BAR 2' 6
'DATA MAX FOR BAR 2' 36
'DATA MIN FOR BAR 2' 5
'COLOUR FOR BAR 3' 4
'DATA MAX FOR BAR 3' 42
'DATA MIN FOR BAR 3' 29
'COLOUR FOR BAR 4' 1
'DATA MAX FOR BAR 4' 31
'DATA MIN FOR BAR4' 12

IV. ' libdiag' and listings 6.10 and 6.11 ('pie', 'hatch', etc.). Data required : for
example

'No . OF SEGMENTS' 3
'COLOUR' 0
'DATAI' 1
'DATA 2'2
'DATA 3' 3
Centre pie with cursor then 'RADIUS (IN PIXELS)' 75
Use cursor to centre wedge 'HATCH' (x , y, b, n) E.: 'JUMP'~: 'REM' ~
Use cursor to centre wedge 'HATCH' (x, y, b, n) y : 'JUMP' 1: 'REM' 0
Use cursor to centre wedge 'HATCH' (x, y, b, n) ~ - -

V. 'libdiag' and listing 6.12 ('graph' , etc.) . The questions posed by the program
are self-explanatory: like those above. .
7 Three-dimensional Coordinate
Geometry

Before we lead on to a study of the graphical display of objects in three-dimen-


sional space, we first have to come to terms with three-dimensional Cartesian
coordinate geometry. As in two-dimensional space, we arbitrarily fix a point in
the space, named the coordinate origin (origin for short). We then imagine three
mutually perpendicular lines through this point ; each line goes off to infinity in
both directions. These are the x-axis, y-axis and z-axis. Each axis is thought to
hav~ a positive and a negative half, both starting at the origin ; that is, distances
measured from the origin along the axis are positive on one side and negative on
the other. We can think of the x-axis andy-axis in a similar way to two-dimen-
sional space, both lying on the page of this book say, the positive x-axis
'horizontal' and to the right of the origin , and the positive y-axis 'vertical' and
above the origin. This just leaves the position of the z-axis: it has to be perpen-
dicular to the page (since it is perpendicular to both the x-axis and the y-axis).
The positive z-axis can be into the page (the so-called left-handed triad of axes)
or out of the page (the right-handed triad) . In this book we always use the left-
handed triad notation . What we say in the remainder of the book about left-
handed axes has its equivalent in the right-handed system - it is not important
which notation you decide finally to use , as long as you are consistent.
We specify a general point P in space by a coordinate triple or vector (X, Y, Z),
where the individual coordinate values are the perpendicular projections of the
point on to the respective x-axis, y-axis and z-axis. By projection we mean the
unique point on the specified axis such that a line from that point to P is perpen-
dicular to that axis.
There are two operations we need to consider for three-dimensional vectors.
Suppose we have two vectors PI == (XI' YI, zd and P2 == (X2' Y2. Z2) then

scalarmultiple k PI == (k x X I , k x Y I , k x Z I) multiply the three individual


coordinate values by a scalar number k
vector addition PI +P2==(XI +X2.YI +Y2. Z1 +Z2) add the x-coordinates
together, then the y-coordinates and finally the z-coordinates to form a new
vector
Three-dimensional Coordinate Geometry 125

Definition of a Straight Line

A straight line in three-dimensional space passing through two such points,


PI == (XI ' YI, Zd andp2 == (X2, h, Z2), is the next object to be defined. We
may do this by describing the coordinates of a general point P == (x, Y, z) on the
line by three equations

(X-XI)X 0'2 - y d = 0' - Y d X (x2 -xd


0' -Ydx (Z2 -zd '=(z-zd X 0'2 -Yd
(z - zd X (X2 - xd = (X - xd X (Z2 - zd

Although these are three equations in three unknowns, we shall find that they are
interrelated (so-called linearly dependent) and so there is no unique solution
(naturally, since we are generating a general point on the line, not just one point).
These equations enable us to calculate two of the coordinates in terms of a third
(see example 7.1).
As with two dimens ions, this is not the only way of representing a line ; in fact
the second way that we introduce is possibly more useful. The general point on
the line is represented as a vector that is dependent on only one real number IJ.,
and is given as the vector sum of two scalar multiples of vectors

that is

This form is exactly equivalent to the two-dimensional parametric form of a


line that we saw in chapter 3. Here we place IJ. in brackets after P to demonstrate
the dependence of P on IJ. ; however, when this concept has been fully investigat-
ed then (p.) will be ignored. Note that when IJ. = 0 the equation returns point PI
and when /l = 1 it gives P2 .
We may rewrite this vector expression as

like its counterpart in two -dimensions , P I is called a base vector and (P2 - PI)
a directional vector. Again we see the dual interpretation of a vector. A vector
can be used to specify uniquely a point in three-dimensional space, or it can be
considered as a general direction; namely, any line parallel to the line that joins
the origin to the vector (considered as a point). We can move along a line in one
of two directions, so we say that the direction from the origin to the point has
positive sense, and from the point to the origin negative sense. Hence vectors
126 Advanced Graphics with the Sinclair ZX Spectrum

d == (x, y, z) and -d == (-x, -y, -z) represent the same line in space but their
directions are of opposite senses. We define the length of a vector d == (x, y , z)
(sometimes called its modulus , or absolute value) as 1dl, the distance of the
point vector from the origin

So any point on the line p + ud is found by moving to the point p and then
travelling along a line that is parallel to the direction d, a distance Jl I d 1in the
positive sense of d if Jl is positive, and in the negative sense otherwise. Note any
point on the line can act as a base vector, and the directional vector may be
replaced by any non-zero scalar multiple of itself.
If the directional vector d == (x, y , z) makes angles Ox , Oy and Oz with the
respective positive x-direction,y-direction and z-direction, then the ratios

x :y :z = cos Ox:cos Oy :cosOz

which means that d == (A x cos Ox, Ax cos Oy, A x cos Oz) for some A.
We know from the properties of three-dimensional geometry that

Hence A= I d I, and if the directional vector has unit modulus (that is, modulus
= A= 1), then the coordinates of this vector must be (cos Ox, cos 0y, cos 0z) ;
that is, A = 1. The coordinates of a directional vector given in this way are called
the direction cosines of the set of lines generated by the vector . In general, if
the direction vector is d == (x, y , z) then the direction cosines are

X y z)
( Tdi'Idi'1di

Example 7.1
Describe the line joining (1,2,3) to (-1 ,0,2), using the three methods shown
so far.
The general point (x, y , z) on the line satisfies the equations

(x - 1) x (0 - 2) = (y - 2) x (-1 - 1) that is, -2x + 2y = 2 (7.1)


(y - 2) x (2- 3) = (z - 3) x (0 - 2) -y + 2z = 4 (7.2)
and (z-3)x(-I-I)=(x-l)x(2-3) -2z+x=-5 (7 .3)

Notice that equation 7.1 is -2 times the sum of equations 7.2 and 7.3. Thus we
need consider only these latter two equations, to get
Three-dimensional Coordinate Geometry 127

y = 2z - 4 and x = 2z - 5

so that the general point on the line depends only on one variable, in this case z,
and is given by (2z - 5, 2z - 4, z) . We easily check this result by noting that
when z = 3 we get (1,2 ,3) and when z = 2 we get (-1 ,0,2), the two original
points defining the line.
In vector form the general point on the line (depending on Jl) is

p(Jl) == (1 - JlHl, 2, 3) + Jl(- 1, 0 , 2) == (1 - 2Jl, 2 - 2Jl, 3 - Jl)

Again the coordinates depend on just one variable (Jl), and to check the validity
of this representation of a line we note that p(O) == (1,2,3) and p(l) == (-1,0,2).
If we put the line into base/directional vector form we see that

p(Jl) == (1,2,3) + Jl(- 2, -2, - 1)

with (1,2,3) as the base vector and (-2, -2, -1) as the direction (which
incidently has modulus y(4 + 4 + 1) = y9= 3) . We noted also that any point on
the line can act as a base vector , and so we can give another form for the general
point on this line,p'

p'(Jl) == (-1 ,0,2) + Jl(-2, - 2, - 1)

We can change the directional vector into its direction cosine form (-2/3 , -2/3 ,
-1/3) and represent the line in another version of the base/direction form

p"(Jl) == (1,2 ,3) + Jl(- 2/3, -2/3 , - 1/3)

Naturally the same Jl value will give different points for different representations
of the line; for example, p(3) == (-5, - 4, 0) , p'(3) == (-7, - 6, -1) and p"(3) ==
(-1,0,2). The direction of this line makes angles of 131.81 degrees = cos"?
(-2/3),131.81 degrees and 109.47 degrees = cos" (-1/3) with the positive
x-direction,y -direction and z-direction respectively .

The Angle Between Two Directional Vectors

In order to calculate such an angle, first we introduce the operator· the dot
product or scalar product. This operates on two vectors and returns a scalar
(real) result. Thus

If p and q are both unit vectors (that is, in direction cosine form), and 8 is the
128 Advanced Graphics with the SinclairZX Spectrum

angle between the lines, then cos () = p • q (see chapter 3 for equivalent two-
dimensional relationship). In general, therefore, the angle between two direction-
al vectors p and q (we can assume they meet at the origin) is

cos
-I (P
IPT . IQT)
q ~

Obviously P and q are mutually perpendicular directions if and only if p • q =O.

Definition of a Plane

The plane is the next object we must consider in three-dimensional space. The
general point x == (x, y, z) on the plane is given by the vector equation

n·x=k

where k is a scalar, and n is the directional vector of the set of lines that are
perpendicular to (or normal to) the plane (see example 7.2). If a is any point
on the plane then naturally n • a = k, and so by replacing k in the above
equation, we can rewrite it as

n • x = n • a or n· (x - a) = 0

This latter equation is self-evident from the property of the dot product, that
two mutually perpendicular lines have zero dot product. For any point x ==
(x, y, z) in the plane that is not equal to a, we know that (x - a) can be
considered as the direction of a line in the plane . Since n is normal to the plane ,
and incidently perpendicular to every line in the plane, then n • (x - a) = cos
(rr/2) = O.
Expanding the original equation of the plane with normal n == (nl, n2, n3),
we get the usual coordinate representation of a plane

Note that two planes with normals nand m (say) are parallel if and only if one
normal is a scalar multiple of the other; that is, n = Am for some A.

The Point of Intersection of a Line and a Plane

Suppose the line is given by b + /ld and the plane by n • x =k . Since the point of
intersection lies on both the line and the plane, we have to find the unique value
of /l (if one exists) for which
Three-dimensional Coordinate Geometry 129

n • (b + Jld) = k

that is, Jl = (k - n • b)/(n • d) provided n • d"* O.


n • d = 0 if the line and plane are parallel and so either there is no point of
intersection or the line is in the plane.

The Distance of a Point from a Plane

The distance of a point Pi from a plane n • x = k is the distance of P 1 from the


nearest point pz on the plane. Hence the normal from the plane at pz must pass
through Pl. This line can be written Pi + un, and the Jl value that defines pz is
such that

Jl = (k - n • pd/(n • n)

from the equation above, and the distance of the point pz =Pi + un from Pi is

JlX Inl= Ik-n'Pil/lnl

In particular, if Pi is the origin 0 then the distance of the plane from the origin
is I k I/ I n I. Furthermore, if n is a direction cosine vector, we see that the distance
of the origin from the plane is I k I, the absolute value of the real number k.

Example 7.2
Find the point of intersection of the line joining (1,2,3) to (-1 ,0,2) with the
plane (0, -2,1)' x = 5, and also find the distance of the plane from the origin.

b =(1 , 2, 3)
n =(0, -2,1)
d = (-1, 0, 2) - (1, 2, 3) =(-2, -2, -1)
n • b = (0 x 1 + - 2 x 2 + 1 x 3) = -1
n • d = (0 x -2 + -2 x - 2 + 1 x-I) = 3

hence the Jl value of the point of intersection is (5 - (-1 ))/3 = 2, and the point
vector is

(1,2,3) + 2(-2, -2, -1) = (-3, - 2, 1)

and the distance from the origin is 5/1nl= 5/..j5 =..j5 .

The program given in listing 7.1 enables us to calculate the point of intersec-
tion (array P) of a line and a plane . The line has base vector B and direction D,
and the plane has normal N and plane constant K. Note, since we are working
with decimal numbers, and thus are subject to rounding errors, we cannot check
130 Advanced Graphics with the Sinclair ZX Spectrum

if a dot product is zero. We can find only if it is sufficiently small to be consider-


ed zero, and what is meant by sufficiently small is left to the programmer (on the
Spectrum about six places after the decimal point is reasonable).
Listing 7.1
100 REM i ~t e r se c t i on of l ine and plane
110 DIM B(3): DIM 0(3): DIM N(3): DIM P (3): DIM A$(8)
120 INPUT "BASE VECTOR OF LINE","( ";B(1);",";B(2);",";B(3);")"
130 PRINT AT 1,0;"BASE VECTOR OF LINE","(";B(1);",";B(2);",";B(3);") "
1~ INPUT "DIRECTION VECTOR OF LINE","(";0(1); ",";0(2);",";0(3); ")"
150 PRINT AT 4,0;"OIRECTION VECTOR OF LINE", "( ";0(1);",";0(2);",";0(3);") "
160 INPUT "NORMAL TO PLANE",,"(";N(1);",";N(2);",";N(3);")"
170 PRINT AT 7,0;"NORMAL TO PLANE",,"( ";N<1);",";N(2);",";N( 3);") "
180 INPUT "PLANE CONSTANT ";K
188 REM calculate point of i nt e r s e c t i on (P(1),P(2),P(3»
189 REM of line and plane, data i nput above.
190 PRINT AT 10,0;"PLANE CONSTANT " ; K
200 LET DOT = N(1)*0(1) + N(2)*0(2) + N(3)*0(3)
209 REM zero dot product so no intersect ion.
210 IF ABS DOT < 0.000001 THEN PRINT AT 15,0;"NO POINT OF INTERSECTION": STOP
220 LET MU = (K - N(1)*B(1) - N(2)*B(2) - N(3)*B(3»/OOT
230 FOR I = 1 TO 3: LET P(I) = B(I) + MU*O(I)
: IF ABS P(I) < 0.000001 THEN LET P(I) = 0
240 NEXT I: PRINT AT 15,0;"POINT OF INTERSECTION ","(";
249 REM tidy up output.
250 FOR I= 1 TO 3: LET A$ = =
STR$ PO): FOR J 1 TO 8
260 IF A$(J) <> " " THEN PRINT A$(J);
270 NEXT J: IF I <> 3 THEN PRINT ",";
280 NEXT I: PRINT " ) "
290 STOP

The Point of Intersection of Two Lines

Suppose we have two lines b 1 + J,J.d 1 and b 2 + "Ad2 • Their point of intersection ,
if it exists (if the lines are not coplanar or are parallel then they will not inter-
sect), is identified by finding unique values for J,J. and "A that satisfy the vector
equation (three separate coordinate equations)

Three equations in two unknowns means that for the equations to be meaningful
there must be at least one pair of equations that are independent, and the
remaining equation must be a combination of these two . Two lines are parallel if
one directional vector is a scalar multiple of the other. So we take two independ-
ent equations, find the values of J,J. and "A (we have two equations in two un-
knowns), and put them in the third equation to see if they are consistent.
Example 7.3 , below, demonstrates this method, and listing 7.2 is a way of
implementing it on a computer. The first line has base and direction stored in
arrays Band D, and the second line in C and E: the calculated point of inter-
section goes into array P.
Note that if the two independent equations are
Three-dimensional Coordinate Geometry 131

all x ll+a12 x "A=b 1


a21 x 11 + a22 x "A = b 2

then the determinant of this pair of equations .t. = a 11 x a22 - a 12 x a2l> will be
non-zero (because the equations are not related), and we have the solutions

Listing 7.2

100 REM int e r se ct ion of t wo li nes


110 DIM B(3): DIM D(3): DIM C(3): DIM E(3): DIM P(3): DIM A$ (8)
120 INPUT "B ASE VECTOR OF FIRST LINE","(";B(1);",";B (2);",";B (3);")"
130 PRINT AT 1,0;"BASE VECTOR OF FIRST LINE","(";B(1);",";B(2);",";B( 3);")"
1/,g INPUT "DIRECTION VECTOR OF FI RST LINE","(";D(1);",";D(2);", ";D(3);")"
150 PRINT AT 4,0;"DIRECTION VECTOR OF FIPST LINE","(";D(1);",";D (2);", ";D(3);")"
160 INPUT "BASE VECTOR OF SECOND LI NE", "( ";C(1); ", ";C(2);",";C(3);")"
170 PR I NT AT 7 ,0;"BASE VECTOR OF SECOND L I NE","(";Ce1); ",";C (2); ",";C(3);")"
180 IN PUT "DIRECTION VECTOR OF SECOND LINE "," (";Ee1 );", ";E ( 2); ",";E (3);")"
190 PRINT AT 10,0; "DIRECTION VECTOR OF SECOND LI NE","( ";E(1);", ";E(2);", ";E(3);")"
198 REM calculate point of i nt e r se ct i on (P(1),P(2) ,P(3»
199 REM of two lines, data input above.
195 REM f in d a ny two inde pendent l ine equa t i ons f rom the three (x/ y/z).
200 FOR I = 1 TO 3
210 LET J = I + 1 : IF J = 4 THEN LET J = 1
220 LET DELTA = E(I)*D(J) - E( J)*D(I)
230 IF ABS DELTA> 0.000001 THEN GO TO 260
2/,g NEXT I
249 REM can not find two i nde pendent equat ions: l ines do not intersect .
250 PRINT AT 15,0; "LINES DO NOT INTERSECT": STOP
259 REM calculat e MU and LAMBDA va lu e s of poi nt of i nt e r se cti on.
260 LET MU = (E(I)*(Ce J) - B( J» - E( J)*eC (I) - B( I» )/DELTA
270 LET LAMBDA = (D(I)*(C( J) - B(J» - D(J)*(C(I) - B( I»)/DELTA
279 REM no solution i f MU and LAMBDA do not sat isf y t hird equati on.
280 LET K = J + 1: IF K = 4 THEN LET K = 1
290 IF ABS (B(K) + MU*D(K) - C(K) - LAMBDA*E(K» > 0.000001 THEN GO TO 250
299 REM calculate (P(1),P(2),P(3» usi ng MU va l ue .
300 FOR I = 1 TO 3: LET P(I) = B(I) + MU*D(I)
: IF ABS PO) < 0.000001 THEN LET PO) = 0
310 NEXT I: PRINT AT 1 5 , 0 ;"POINT OF I NTERSECTION " ," ( " ;
319 REM tidy up output.
320 FOR 1=1 TO 3: LET A$ = STR$ pel>: FOR J = 1 TO 8
330 IF A$(J) <> " " THEN PRINT A$(J);
3/,g NEXT J: IF I <> 3 THEN PRINT ",";
350 NEXT I : PR INT ")"
360 STOP

Example 7.3
Find the point of intersection (if any) of

(a) (1,1 ,1)+11(2,1 ,3) with (0,0, 1)+"A(-I , 1,1),


(b) (2,3,4) + 11(1 ,1 ,1) with (-2 , - 3, - 4) + "A(I, 2,3).
132 Advanced Graphics with the SinclairZX Spectrum

In (a) the three equations are

1+21J=0 -X (7.4)
1+ IJ=O+X (7.5)
1 + 31J = 1 + X (7.6)

From equations 7.4 and 7.5 we get IJ= - 2/3 and X= 1/3 , which when substituted
in equation 7.6 gives 1 + 3 x (-2/3) = -Ion the left-hand side and 1 + 1 x (1/3)
=4/3 on the right-hand side, which are obviously unequal , so the lines do not
intersect. From (b) we get the equations

2 + IJ = - 2 + X (7.7)
3 + IJ = -3 + 2X (7.8)
4 + IJ= - 4 + 3X (7.9)

and from equations 7.7 and 7.8 we get IJ = - 2 and X= 2, and these values also
satisfy equation 7.9 (left-hand side = right-hand side = 2). So the point of
intersection is

(2 ,3,4) + -2(1,1 ,1) = (-2, - 3, - 4) + 2(1, 2, 3) = (0,1 ,2)

The Plane Through Three Non-collinear Points

In order to solve this problem we must introduct a new vector operator, X the
vector product, which operates on two vectors p and q (say) giving the vector
result

p Xq = (Pt , P2, P3) X (qt, q2, q3)


=(P2 x q3 -P3 X q2,P3 X qt -PtX q3,Pt x q2 - P2 x qd

If p and q are non-parallel directional vectors then p X q is the directional vector


perpendicular to both p and q. It should be noted also that this operation is
non-commutative. That is, in general for given values of p and q , we note that
p X q =1= q X p. These two vector products will represent directions on the same
line but with opposite senses. For example , (1,0,0) X (0, 1,0) = (0, 0, 1) but
(0,1 ,0) X (1,0,0) = (0, 0, -1); (0,0,1) and (0, 0, - 1) are both parallel to the
z-axis (and so perpendicular to the directions (1,0,0) and (0 , 1,0)), but they are
of opposite senses. Listing 7.3 givesa main program that calls the routines
'vecprod' (for the vector product of two vectors Land M returning vector N)
and 'dotprod' (which calculates the dot product DOT of the vectors Land M),
both given in listing 7.4.
Three-dimensional Coordinate Geometry 133

Listing 7.3
10~ REM dot product and vector product
110 LET vecprod =
3~~: LET dotprod 40~ =
120 DIM L(3): DIM M(3): DIM N(3)
130 INPUT "VECTOR L","(";U1);",";L<Z);",";U3);")"
140 PRINT AT 1,0;"VECTOR L","(";U1);",";U2);",";L<3);")"
150 INPUT "VECTOR M","(";M(1);",";M(Z);",";M(3);")"
160 PRINT AT 4,0;"VECTOR M","(";M(1);",";M(2);",";M(3);")"
170 GO SUB vecprod
180 PRINT AT 8,1lI;"VECTOR PRODUCT","(";N(1);",";N(2);",";N(3);")"
190 GO SUB dot prod
20~ PRINT AT 11,0;"DOT PRODUCT",DOT
210 STOP

Listing 7.4
30~ REM vecprod
301 REM IN : L(3),M(3)
302 REM OUT : N(3)
309 REM N is the vector product of Land M.
310 LET NI = 2: LET NNI 3=
320 FOR I = 1 TO 3
330 LET N(I) =L(NI)*M(NNI)-L(NNI)*M(NI)
340 LET NI = NNI: LET NNI =
IH + 1 : IF NNI = 4 THEN LET NNI =1
350 NEXT I
360 RETURN

4111~ REM dot prod


401 REM IN : L(3),M(3)
402 REM OUT : DOT
41119 REM DOT is the dot pr cdu ct of Land M.
410 LET DOT =0
420 FOR I = 1 TO 3: LET DOT =
DOT + L(I)*M(I): NEXT I
430 RETURN

Suppose we are given three non-collinear points P I, P2 and P3' Then the two
vectors P2 - PI and P 3 - P 1 represent the directions of two lines coincident at
PI, both of which lie in the plane containing the three points. We know that the
normal to the plane is perpendicular to every line in the plane, in particular the
two lines mentioned above. Also, because the points are not collinear P2 - PI =1=
P3 - PI, the normal to the plane is (P2 - PI) X (P3 - P1), and since PI lies in
the plane the equation is

Example 7.4
Give the coordinate equation of the plane through the points (0, 1, 1), (1,2,3)
and (-2, 3, -1).
This is given by the general point x == (x, y, z) where

«(1,2,3) - (0,1,1)) X «-2, 3, - 1) - (0,1,1)))· «x,y, z) - (0,1,1)) =0


134 Advanced Graphics with the Sinclair ZX Spectrum

that is

((1, 1,2) X (-2,2, -2) • (x, y - 1, z - 1) = 0

or

(-6, -2,4)' (x,y -I,z -1) = a

which in coordinate form is -6x - 2y + 4z - 2 = 0 or in the equivalent form


3x +y - 2z = -1.

ThePointof Intersection of Three Planes

We assume that the three planes are defined by equations 7.10 to 7.12 below.
The point of intersection of these three planes, x == (x, y, z), must lie in all
three planes and satisfy

(7.10)
n2 • x =k2 (7.11)
n3 • x =k 3 (7.12)

where nl == (nIb n12, nI3),n2 == (n2l> n22, n23) and n3 == (n31, n32, n33)' We
can rewrite these three equations as one matrix equation

and so the solution for x is given by the column vector

So any calculation requiring the intersection of three planes necessarily involves


the inversion of a 3 X 3 matrix. listing 7.5 gives the Adjoint method of flnding
M, the inverse of matrix N.
Three-dimensional Coordinate Geometry 135

Listing 7.5
50VJ REI': inv/er se of 3x3 matrix
501 IN : N<3,3)
502 OUT: SINGULAR, M(3,3)
510 LET SINGULAR = 1
520 LET DET = 0: LET NI = 2: LET NNI = 3
530 FOR I = 1 TO 3
540 LET DET = DET + N(1,I)*(N(2,NI)*N(3,NNI)-N(2,NNI)*N(3,NI»
550 LET NI = NNI: LET NNI = NI + 1 : IF NNI = 4 THEN LET NNI = 1
560 NEXT I
569 REM DETerminant of singular matr ix is zero, th ere is no inverse .
570 IF ABS DET < 0.000001 THEN RETURN
579 REM calculate M, the inverse of N, by the Adjoint method.
580 LET NI = 2: LET NNI = 3
590 FOR I = 1 TO 3
600 LET NJ = 2: LET NNJ = 3
610 FOR J = 1 TO 3
620 LET M(J,n = (N(NI,NJ)*N(NNI,NNJ) - N(NI,NNJ)*N(NNI,NJ»/DET
630 LET NJ = NNJ: LET NNJ = NJ + 1: IF NNJ = 4 THEN LET NNJ = 1
640 NEXT J
650 LET NI = NNI: LET NNI = NI + 1: IF NNI = 4 THEN LET NNI = 1
6611l NEXT I
6711l LET SINGULAR =
0
680 RETURN

Again in this routine, vectors are represented as one-dimensional arrays, thus


B(3) contains the solution of the equations, x , while K(3) contains the plane
constants. We are given the normals n., n2 and a, in the form ofa 3 X 3 array
N, so the values in B are found by the following code. Obviously if any two of
Listing Z6
11110 REM intersect icn of three planes
1111l DIM N(3,3): DIM M(3,3): DIM K(3): DIM B(3)
120 LET °i nv = 500
129 REM input data on three planes.
Bill PRINT AT 2,1 Ill;"COEFFICIENTS CONSTANT"
140 FOR I = 1 TO 3
150 PRINT AT 2 + 2*I,0;"PLANE(";I;") = ( )"
1611l FOR J = 1 TO 3
1711l LET IS = "INPUT N(" + STR$ I + "," + STRS J + ") "
1811l INPUT (IS) ;N(I,J): PRINT AT 2 + 2*1,7 + 4*J;N(I,J)
190 NEXT J
200 LET !~ ~ "INPUT K(" + STRS I + ") "
210 INPUT (IS);K(I): PRINT AT 2 + 2*I,28;K(I)
2211l NEXT I
229 REM if matrix of normals i s s ingular then no i nt e r se ct ; on.
2311l GO SUB i nv
240 PRINT AT 12,3; "POINT OF INTERSECTION"
250 IF SINGULAR THEN PRINT AT 12,0;"NO": STOP
259 REM point of intersection is (B(1),B(2),B(3».
260 FOR I = 1 TO 3
2711l LET B(I) = 0
280 FOR J = 1 TO 3
290 LET B(I) = B(I) + M(I,J)*K(J)
311l1ll NEXT J
3111l IF ABS B(1) < 0.000011l1 THEN LET B(I) = 0
320 PRINT AT 12 + 2*I,7;"B(";I;") = ";B(1)
330 NEXT I
340 STOP
136 AdvancedGraphics with the Sinclair ZX Spectrum

the planes are parallel or the three meet in a line, then there is no unique point
of intersection : in these cases DET, the determinant of the matrix N is zero and
variable SINGULAR = I . (See listing 7.6.)

Example 7.5
Find the point of intersection of the three planes (0, I , I) " x = 2, (1 ,2,3) " x =
4and(l , I, 1)"x=O.
In the matrix form we have

The inverse of G ; ;) is ( -; _~ ~)
I 1 -1 1-1

and so

G) = C~ -: -1) X mCD =

This solution is easily checked : (0, 1,1) " (-2, 0, 2) = 2, (1,2,3) " (-2, 0, 2)
= 4 and (1 , 1, I) " (-2, 0 , 2) = 0 , which means the point (-2, 0, 2) lies on all
three planes and so is their point of intersection.

The Line of Intersection of Two Planes

Let the two planes be

p "X = (PI, P2. P3)' x = k l and


q " x = (q1> Q2 . Q3) • x = k 2

Weassume that the planes are not parallel, and so p =:/= 'Aq for all 'A. The line
common to the two planes naturally lies in each plane, and so it must be per-
pendicular to the normals of both planes (p and q). Thus the direction of this
line must be d == p X q and the line can be written in the form b + IJd, where b
can be any point on the line. In order to classify completely the line, we have to
find one such b. We find a point that is the intersection of the two planes,
together with a third that is neither parallel to them nor cuts them in a common
line. Choosing a plane with normal p X q will satisfy these conditions (and
Three-dimensional Coordinate Geometry 137

remember that we have already calculated this vector product). We still need a
value for k 3 , but any will do, so we take k 3 = 0 in order that this third plane
goes through the origin . Thus b is given by the column vector

Example 7.6
Find the line common to the planes (0, 1, 1) • x = 2 and (1,2,3) • x = 2. Since
p = (0 ,1 , 1) and q = (1,2,3), then p X q = (1 x 3 - 1 X 2 , 1 x 1 - 0 x 3,0 x
2 - 1 x 1) = (1, 1, -1). We require the inverse of

0 1
I 2
( 1 1

and hence the point of intersection of the three planes is

(-521) (2)~ ~ (-6)~ (-2)~


~ _~ -~ _~ X = =

and the line is (-2,2,0) + J,t(1, 1, -1).


It is easy to check this result, because all the points on the line should lie in
both planes

(0, 1, 1) • ((-2,2,0) + J,t(1 , 1, -1» = (0, 1, 1) • (-2,2,0) + J,t(0, 1, 1) •


• (1, 1,-1)=2 for all u and
(1,2,3)' ((-2,2,0) + J,t(1, 1, -1» = (0,1,1)' (-2,2,0) + J,t(1, 2, 3)'
'(1,1,-1)=2 for all u

The program to solve this problem (listing 7.7) is given below; note it is very
similar to the previous program. Also note that arrays are not explicitly used for
p and q, these values are stored in the rust two rows of array N. Array B holds
the base vector of the line of intersection, but we do not place d in an array
because the values are already in the third row of N.

Functional Representation of a Surface

In our study of two-dimensional space in chapter 3 we noted that curves can be


represented in a functional notation. This idea can be extended into three
138 Advanced Graphics with the Sinclair ZX Spectrum

Listing 7.7
100 REM Line of intersection of two pLanes
110 DIM N(3,3 ): DIM M(3,3): DIM K(3) : DIM B(3): DI~ A$(2)
120 LET inv = 50rJ: LET AS = "PQ"
129 REM i nput data on two pLanes.
130 PR INT AT 2, 10i "COEFFICI ENTS CONSTANT"
140 FOR I = 1 TO 2
150 PRINT AT 2 + 2*I,lIli"PLANE("iIi")= ( , , )"
160 FOR J = 1 TO 3
1711l LET IS = "INPUT " + ASO) + "(" + STRS J + " ) "
180 INPUT (IS)iN(I,J): PRINT AT 2 + 2*1,7 + 4*JiN(I,J)
190 NEXT J
200 LET IS = "INPUT K(" + STRS I + ") "
210 INPUT (IS) ;K(I): PRINT AT 2 + 2*I ,28iK(I)
220 NEXT I
229 REM form t~i rd pLane.
230 LET N(3,1) = N(1,2)*N(2,3) - N(1,3)*N(2,2)
240 LET N(3,2) = N(1,3)*N(2,1) - N(1,1)*N(2,3)
250 LET N(3,3) = N(1,1)*N(2,2) - N(1,2)*N(2,1)
260 LET K(3) = III
269 REM if matrix of normaLs is singuLar then no intersection.
270 GO SUB i nv
280 PRINT AT 10, 3i "LINE OF INTERSECTION"
2911l IF S :~ElLAR THEN PRINT AT 10,0i"NO": STOP
311J0 PR!ln AT 12,2i"BASE VECTOR DIRECTION"
308 REM Line of intersect icn : -
309 REM base (B(1) , B( 2) , B(3» and direction (N(3,1),N(3,2),N(3,3».
310 FOR I = 1 TO 3
320 LET 80) = e
330 FOR J = 1 TO 3
340 LET B(I) = B(I) + M(I,J)*K(J)
350 NEXT J
360 IF ABS B(I) < 0.1Il01'!0rJ1 THEN LET eO) = 0
370 PRINT AT 12 + 2*I,lIli "B{ "iii") = " i B( I)
380 PRINT AT 12 + 2*1,20;"D("ili") = "iN(3,1)
390 NE XT I
40rJ STOP

dimensions when we study surfaces. The simplest form of surface is an infinite


plane with normal n == (n!, ns . n3) , which we have seen can be given as a co-
ordinate equation

n • x - k = n! x x + n2 x Y + n3 x z - k =0
This can be rewritten in functional form for a general point x == (x, y, z) on the
curve

[(x) == [(x, y , z) == n! x x + n2 x Y + n 3 x z - k == n • x - k

This is a simple expression in variables x, y and z (x) that enables us to divide all
the points in space into three sets, those with [(x) = 0 (the zero set) , with
[(x) < 0 (the negative set) and [(x) > 0 (the positive set). A point x lies on the
surface if and only if it belongs to the zero set. If the surface divides space into
two halves (each half being connected; that is, any two points in a given half can
Three-dimensional Coordinate Geometry 139

be joined by a curve that does not cross the surface) , then these two halves may
be identified with the positive and negative sets. Again beware, there are many
curves that divide space into more than two connected areas and then it is
impossible to relate functional representation with connected sets; for example,
[(x, y, z) = cos (y) - sin (x 2 + Z2). There are, however, many useful well-behaved
curves with this property, the sphere of radius r for example

that is,

[(x,y,z)=r 2 _x2 _ y 2 _ Z2

If [(x) = 0 then x lies on the sphere, if [(x) < 0 then x lies outside the sphere,
°
and if [(x) > then x lies inside the sphere.
The functional representation of a surface is a very useful concept. It can be
used to define sets of equations necessary in calculating the intersections of
various objects. The major use, however, is to determine whether or not two
points P and q (say) lie on the same side of a surface that divides space in two.
All we need do is compare the signs of [(P) and [(q). If they are of opposite
signs then a line joiningp and q must cut the surface. An example is given below.

Is a Point on the Same Side of a Plane as the Origin?

Suppose the plane is defined (as earlier) by three non-collinear points Pi, P2 and
P3' Then the equation of the plane is

We may rewrite this in functional form

So all we need do for a point e (say) is to compare [(e) with [(0) , where 0 is
the origin. We assume here that neither 0 nor e lie in the plane .
We shall see that this idea is of great use in the study of hidden line algorithms.

Example 7.7
Are the origin and point (1, 1, 3) on the same side of the plane defined by points
(0,1 ,1), (1, 2,3) and (-2,3, -I)?
From example 7.4 we see that the functional representation of the plane is

[(x) == (( -6 , -2,4) • (x - (0,1,1»


140 Advanced Graphics with the SinclairZX Spectrum

Thus

[(0,0,0) = - (-6, - 2, 4) ' (0,1,1) =-2

and

[(1 ,1 ,3) = (-6 , - 2, 4) ' (1,1 ,3) - (0,1,1)) = 2

Hence (1, 1,3) lies on the opposite side of the plane to the origin and so a line
segment joining the two points will cut the plane at a point (1 -/l) (0, 0, 0) +
/l(1, 1,3) where 0 <u < 1.

Is an Oriented Convex Polygon of Vertices in Two-dimensional Space Clockwise


or Anti-clockwise?

We start by assuming that the polygon is a triangle defined by the three vertices
Pi == (Xl ' Yl),PZ == (Xz. Yz) and p , == (X3 . Y3 )' Although these points are in
two-dimensional space we can assume they lie in the xjy plane through the
origin of three-dimensional space by giving them all a z-coordinate value of zero.
We systematically define the directions of the edges of the polygon to be
(Pz - pd, (P3 - pz) and (Pi - P3)' Since these lines all lie in the x/y plane
through the origin we know that for all i = 1, 2 or 3 and for some real numbers
ri that depend on i

This is because this vector product is perpendicular to the xly plane and so only
z-coordinate values can be non-zero. The addition of subscripts is modulo 3.
Because the vertices were taken systematically, note that the signs of these ri
values are always the same - but what is more important, if the Pi are clockwise
then the rl are all negative, and if the PI are anti-clockwise the rj are all positive.
Given an oriented convex polygon, we need consider only the first three
vertices to find if it is clockwise or anti-clockwise . This technique will prove to
be invaluable when we deal with hidden line and surface algorithms later in this
book. Listing 7.8 allows us to find whether or not three ordered two-dimensional
vertices form an anti-clockwise triangle.

Example 7.8
Why is the polygon given in example 3.4 anti-clockwise?
The vertices (considered in three dimensions) are (1 ,0,0), (5,2,0), (4 , 4, 0)
and (-2 ,1 ,0). The directions of the edges are (4, 2, 0) , (-1,2,0), (-6, -3,0)
and (3, -1,0). Then, since
Three-dimensional Coordinate Geometry 141

Listing 7.8
10~ REM orientation of 2-D tr iangle
110 DI~ X(3): DI~ Y(3)
120 LET H = "TYPE IN COORDINATES OF TRIAtlGLE "
13~ FOR I = 1 TO 3
140 LET IS = "VERTEX(" + STR$ I + ")= ("
150 INPUT (J$ + IS)iX(I)i","iYCI)i") "
16~ P RINT AT 2 + 2*I,0il$iXCI)i","iY(I)i")"
1i'~ NEXT I
180 PRINT AT 12,0i"THE TRIANGLE I~ "t
188 REM (DX1,DY1) is 2-D direction vector jcining point 1 to point 2 .
189 REM CDX2,DY2) ; !, (-0 direction ve ctor j oi rrinq point 2 to point 3.
1ge LET DX1 =X(2) - X(1): LET DY1 =Y(2) - Y(1)
20~ LET DX2 = X(3) - X(2): LET DY2 = Y(3) - Y(Z)
209 REM use 3 -D vector product to check on orientation of triangle.
2Hl IF DX1*DY2 - DX2*DY1 > ~ THEN PRINT "ANTI-"i
220 PR INT "CLOCKWISE": STOP

(4,2,O)X(-1,2,O) =(0 ,0,10)


(-1,2,0) X(-6,-3,0)=(0,0, 15)
(-6,-3,0)X(3,-1,0) =(0,0,15)
(3, -1,0) X (4, 2, 0) = (0, 0,10)

are all positive, so the orientation of the polygon is anti-clockwise. But be care-
fu1, if you lose this consistent order for calculatingthe vector product you can
get the wrong answer. For example

(-6, -3,0) X (4, 2, 0) = (0, 0, 0) - the lines are parallel!


or (-1,2,0) X (3 , -1,0) = (0 , 0, -5) - we have taken the edges out of
sequence

Complete Programs

I. Listing 7.1 (intersection of line and plane). Data required: a base vector
(B(l), B(2), B(3)) and direction vector (D(1), D(2), D(3)) for the line, a
normal (N(1), N(2), N(3)) and constant K for the plane. Try (1,2,3),
(1,1, -1), (1,0 ,1) and 2 respectively.
II. Listing 7.2 (intersection of two lines). Data required: a base and direction
vectors for the two lines. (B(1), B(2), B(3)) and (D(1), D(2) , D(3)), and
(C(1) , C(2) , C(3)) and (E(1), E(2), E(3)). Try (1,2,3), (1, 1, -1), and
(-1,1,3), (1, 0,1).
III. Listings 7.3 and 7.4 (main program, 'vecprod' and 'dotprod'). Data required:
two vectors (L(1), L(2), L(3)) and (M(l), M(2), M(3)). Try (1, 2, 3),
(1,1, -1).
142 Advanced Graphics with the SinclairZX Spectrum

IV. Listings 7.5 ('inv') and 7.6 (intersection of three planes). Data required:
normal (N(I, 1), N(I, 2), N(I, 3» and constant K(I) for the three planes,
1 ~I ~3 . Try (1, 2, 3), 0,(1 ,1, -1),1,(1,0 ,1),2.
V. Listings 7.5 ('inv') and 7.7 (intersection of two planes). Data required :
normal (N(I, 1), N(I, 2), N(I, 3» and constant K(I) for the two planes,
1 ~1~2. Try(I,2,3),0,(l, 1,-1), 1.
IV. Listing 7.8 (orientation of2-D triangle). Data required: the vertices
(X(I), YO» , 1 ~ I ~ 3. Try (1,2), (2, 3) and (-1 , 1).
8 Matrix Representation of
Transformations on Three-
dimensional Space

In chapter 4 we saw the need for transforming objects in two-dimensional space.


When we draw three-dimensional pictures there will be many times when we need
to make the equivalent linear transformations on three-dimensional space. As in
the lower dimension, there are three basic types of transformation: translation,
scaling and rotation . We shall represent transformations as square matrices (now
they will be 4 X 4). A general point in space relative to a fixed coordinate triad,
the row vector (x, y, Z), must be considered as a four-rowed column vector

All the operations on matrices (addition, scalar multiple, transpose, premulti-


plication of a column vector and matrix product) that we saw in chapter 4 are
easily extended to cope with 4 X 4 matr ices and column vectors by simply
changing the upper bound of the index ranges from 3 to 4 . In this way we can
generate a routine 'mult3' for multiplying two 4 X 4 matrices together. It is
exactly equivalent to routine 'mult2' in the two-dimensional case, and for the
very same reasons. The routine multiplies matrix A by matrix R givingmatrix B,
which is then copied into R . We also need the routine 'idR3', which sets R to
the identity matrix (see listing 8.1).
Consider the case of a general linear transformation on points in three -
dimensional space. A point (x, y , z) - 'before' - is transformed into (x', y', z')
- 'after' - according to three linear equations

x' =A ll X X +A 12 X Y +A 1 3 X Z +A 14
y' =A 2 1 X X +A 2 2 X Y +A 2 3 X Z +A 24
Z' =A 3 1 X X +A 32 X Y +A 3 3 X Z +A 3 4

and as usual we add the extra equation


144 Advanced Graphics with the Sinclair ZX Spectrum

Listing 8.1
9100 REM roul t3
91r1 REM IN : AC4,4),RC4,4)
9102 REM OUT : RC4,4)
9110 FOR I = 1 TO 4
9120 FOR J = 1 TO 4
9130 LET AF = 0
91411 FOR K = 1 TO 4
9150 LET AR = AR + ACI,K)*RCK, J)
9160 NEXT K
9170 LET BCI,J) = AR
9180 NEXT J
91 <)g NEXT I
9200 FOR I = 1 TO 4
9210 FOR J = 1 TO 4
9220 LET RCI,J) = BCI,J)
9230 NEXT J
92411 NEXT I
9250 RETURN
9300 REM idR3
9302 RE~ OUT : RC4,4)
9310 FOR I = 1 TO 4
9320 FOR J = 1 TO 4
9330 LET R(I,J) = 0
93411 NEXT J
9350 LET R(I,I) = 1
9360 NEXT I
9370 RETURN

which if it is to be true for all x, y and z means A 4 1 =A 4 2 =A 4 3 =0 and A 4 4


=1.
Then the equations may be written as a matrix equation where a column
vector representing the 'after' point is the product of a matrix and the 'before'
column vector

So if we store the transformation as a matrix, we can transform every required


point by considering it as a column vector and premultiplying it by a transforma-
tion matrix. As before, transformations may be combined simply by obeying the
sequence of transformations in order . If their equivalent matrices are A, B, C,. . .,
L, M, N, then the matrix equivalent to the combination is N X M X LX . . . X
ex B X A . Remember the order. Since we are premultiplying a column vector ,
then the first transformation appears on the right of the matrix product and the
last on the left .
Matrix Representation of Transformations on Three-dimensional Space 145

Translation

Every point to be transformed is moved by a vector (TX, TY , TZ) say. This


produces the following equations relating the 'before' and 'after' coordinates

X' = 1 x x + 0 x y + 0 x z + TX
y' =0 x x + 1 x y + 0 x z + TY
z' =0 x x + 0 x y + 1 x z + TZ

so that the matrix describing the translation is

o1
0 0
1 0
TX)
TY
( 0 o
1 TZ
000 1

The routine 'tran3' for producing such a matrix A , given the parameters TX, TY
and TZ is given in listing 8.2.

Listing 8.2
90rJrl REM tran3
90rJ1 REM IN : TX, TV, TZ
90rl2 REM OUT: A(4,4)
90HI FOR I = 1 TO 4
9020 FOR J =
1 TO 4
9030 LET A(I,J) 0 =
90t,g NEXT J
9050 LET AU,1) 1 =
9060 NEXT I
9070 LET A(1,4) =
TX: LET A(2,4) = TY: LET A(3,4) = TZ
9080 RETURN

Scaling

The x-coordinate of every point to be transformed is scaled by a factor SX, the


y-coordinate by SY and the z-coordinate by SZ, thus

x' = SX x x + 0 x y + 0 x z + 0
y' = 0 x x + SY x y + 0 x z + 0
Z' = 0 X X + 0 x y + SZ x z + 0

giving the matrix

o
SY
o
o
146 Advanced Graphics with the SinclairZX Spectrum

Usually the scalingvalues are positive, but if any of the values are negative then
this leads to a reflection as well as (possibly) scaling. For example, if SX =-1
and SY =SZ = 1 then points are reflected in the y/z plane through the origin. A
routine 'scale3' to produce such a scaling matrix A given SX, SY and SZ is given
in listing 8.3.

Listing 8.3
8901' REM scaLe3
8901 REM IN : SX,SY,SZ
8902 REM OUT : A(4,4)
8910 FOR I = 1 TO 4
8920 FOR J = 1 TO 4
8930 LET A(I,J) = 0
8940 NEXT J
8950 NEXT I
8960 LET A(1,1) = SX: LET A(2,2) = SY: LET A(3,3) = SZ
8970 LET A(4,4) = 1
8980 RETURN

Rotation about a Coordinate Axis

In order to consider the rotation about a general axis p + IJq by a given angle, it
is first necessary to simplify the problem by considering rotation about one of
the coordinate axes.

\lLx
x z
x z

z y
z-axis into page y-axis into page x-axis into page

(a) (b) (c)

Figure 8.1

(a) Rotation by an angle (J about the x-axis

Referring to figure 8.1c, the axis of rotation is perpendicular to the page (the
positive x-axis being into the page), and since we are using left-handed axes the
figure shows the point (x' , y', a') resulting from the transformation of an arbitrary
point (x, y, z). We see that the rotation actually reduces to a two-dimensional
rotation in they/z plane passing through the point; that is, after the rotation the
x-coordinate remains unchanged. Using the ideas explained in chapter 4 we have
the following equations
Matrix Representation of Transformations on Three-dimensional Space 147

x'=x
y' = cos (J x y - sin (J x z
z' = sin (J x y + cos (J x z

and thus the matrix is

o o

D
cos (J -sin (J
sin (J cos (J
o o

(b) Rotation by an angle (J about the y-axis

Referring to figure 8.1 b, we now have the positive j-axis into the page and,
because of the left-handedness of the axes, the positive z-axis is horizontal and
to the right of the origin while the positive x-axis is above the origin. This leads
us to the equations

x' = sin (J x z + cos (J x x


y'=y
Z = cos (J x z - sin (J x x
I

which gives the matrix

COS (J 0 sin (J
o 1 o
(
- sin (J 0 cos (J
o 0 o

(c) Rotation by an angle (J about the z-axis

Referring to figure 8.1c we get the equations

x' = cos (J x x - sin (J x y


y' = sin (J x x + cos (J x y
z' =z

and the matrix

COS (J -sin (J
sin (J cos (J
(
o o
o o
148 Advanced Graphics with the Sinclair ZX Spectrum

A subprogram 'rot3' to produce such a matrix A, given the angle THETA and
the axis number AXIS (AXIS = I for the x-axis, AXIS =2 for the y-axis and
AXIS = 3 for the z-axis) is given in listing 8.4 .

Listing 8.4

8600 REM rot3


8601 REM IN : THETA, AXIS
8602 REM OUT : A(4,4)
8610 FOR I = 1 TO 4
8620 FOR J = 1 TO 4
8630 LET A(I,J) = 0
8640 NEXT J
8650 NEXT I
8660 LET A(4,4) = 1: LET A(AXIS,AXIS) = 1
8670 LET AX1 = AXIS + 1: IFAX1 = 4 THEN LET AX1 = 1
8680 LET AX2 = AX1 + 1: IFAX2 = 4 THEN LET AX2 = 1
8690 LET CT = COS THETA :LET ST = SIN THETA
8700 LET A(AX1,AX1) = CT: LET A(AX2,AX2) = CT
8710 LET A(AX1,AX2) = -ST: LET A(AX2,AX1) = ST
8720 RETU~N

Inverse Transformations

Before we can consider the general rotation transformation, it is necessary to


look at inverse transformations. An inverse transformation returns the points
transformed by a given transformation back to their original position. If a trans-
formation is represented by a matrix A, then the inverse transformation is given
by matrix A -1 , the inverse of A. There is no need to explicitly calculate the
inverse of a matrix using such techniques as the Adjoint Method (listing 7.5): we
can use listings 8.2, 8.3 and 8.4 with parameters derived from the parameters of
the original transformation

(l) A translation by (TX, TY, TZ) is inverted with a translation by (- TX, - TY,
-TZ);
(2) a scaling by SX, SY and SZ is inverted with a scaling by l/SX, l/SY and
l/SZ ;
(3) a rotation by an angle 8 about a given axis is inverted with a rotation by an
angle -8 about the same axis;
(4) if the transformation matrix is the product of a number of translation,
scaling and rotation matrices A X B X ex ... X L X M X N, then the inverse
transformation is
Matrix Representation of Transformations on Three-dimensional Space 149

Rotation of Points by an Angle 'Y about a General Axis p + uq

Assume p == (PX, PY, PZ) and q == (QX, QY, QZ) . We break down the task into a
number of sub tasks

(a) We translate all of space so that the axis of rotation goes through the origin .
This is achieved by adding a vector -p to every point in space with a matrix F
say , which is generated by a call to 'tran3' with parameters TX = -PX, TY = -PY
and TZ = -PZ . The inverse matrix F- l will be needed later and is found by a call
to 'tran3' with parameters PX , PY and PZ. After this transformation the axis of
rotation is the line 0 + uq passing through the origin .

F=
1 0 0 -PX)
0 1 0 -PY
( o 0 1 -PZ
rl = I 00
(1 0 0 PX)
1 0 PY
0 1 PZ
0001 1
0 0 0 1

(b) We then rotate space about the z-axis by an angle -0:, where (ALPHA =) 0: =
tan"! (QY/QX), given by the matrix G. The matrix is generated by a call to
'rot3', setting THETA = -ALPHA and AXIS = 3, and the inverse matrix G- l by
a call to 'roB ' with THETA = ALPHA and AXIS =3 . At this stage the axis of
rotation is a line lying in the xlz plane passing through the point (v, 0, QZ) .

QX QY 0 0) (QX -QY 0 0)
G =~ -QY QX 0 0 c:' = ~ QY QX 0 0
v
( 0 0 vO v 0 0 vO
o OOv OOOv

where v is the positive number given by v2 = QX2 + Qy 2 .


(c) We now rotate space about the y -axis by an angle -~, where (BETA =) ~ =
tan - I (v/QZ) , given by the matrix H. This matrix is generated by a call to
'rot3 ' with parameters AXIS =2 and THETA = -BETA, and the inverse matrix
tt:' by a call to 'roB ' with parameters AXIS =2 and THETA =BETA.

QZ 0 -v 0)
H- l O w 0 0 H- l _
(QZ 0 v
lOw a 0
0)
w ( v 0 QZ 0 w -v a QZ a
0001 0001

where w is the positive number given by w2 =v2 + QZ2 =QX 2 + Qy2 + QZ2 .
SO the point (v , 0, QZ) is transformed to (0, 0 , w) , hence the axis of rotation is
along the a-axis .
(d) We can now rotate space by an angle 'Y (GAMMA) about the axis of rotation
using matrix W generated by 'roB ' (with AXIS = 3 and THETA = GAMMA).
I)
150 Advanced Graphics with the Sinclair ZX Spectrum

COS 'Y
W = sin 'Y
-sin 'Y
cos 'Y
°° I
o ° °
° °
( I
o I

(e) We need to return the axis of rotation to its original position so we multiply
B- 1 , c:' and finally F- l •

Thus the final matrix P that rotates space by the angle 'Y about the axis
p + uq is P =F- l X G- l X B- 1 X W X H X G X F. Naturally some of these
matrices may reduce to the identity matrix in some special cases, and can be
ignored . For example, if the axis of rotation goes through the origin then F and
p-l are identical to the identity matrix I, and can be ignored.
So it is possible to write a special routine 'genrot' (listing 8.5) that achieves
this rotation and returns the required matrix P given GAMMA, (PX, PY, PZ) and
(QX, QY, QZ).

Listing 8.5
5800 REM genrot
5801 REM IN : PX,PY,PZ,QX,QY,QZ,GAMMA,R(4,4)
5802 REM OUT : R(4,4)
5809 REM pla ce origin on a xis of rotation.
5810 LET TX = -PX: LET TY = -PY: LET TZ = -PZ: GO SUB tran3: GO SUB mult3
5819 REM rotate axis of rotation into x / z plane.
5820 LET AX = QX: LET AY = QY: GO SUB angle
5830 LET ALPHA = THETA: LET THETA = -THETA: LET AXIS = 3: GO SUB rot3
: GO SUB mul t3
5839 REM rotate axis of rotat ion onto z-axis.
584la LET AX = QZ: LET AY = SQR (QX*QX + QY*GY): GO SUB angle
5850 LET BETA = THETA: LET THETA = -THETA: LET AXIS = 2: GO SUB rot3
: GO SUB mul t3
5859 REM rotate by GAMMA about axis of rotation.
5860 LET AXIS = 3: LET THETA = GAMMA: GO SUB rot3: GO SUB mult3
5869 REM replace axis back to or iginal position.
5870 LET AXIS = 2: LET THETA = BETA: GO SUB rot3: GO SUB mult3
5880 LET AXIS = 3: LET THETA = ALPHA: GO SUB rot3: GO SUB mult3
5890 LET TX = PX: LET TY = PY: LET TZ = PZ: GO SUB tran3: GO SUB mul t3
5900 RETURN

EXQmple8.1
What happens to the points (0, 0 , 0), (1,0,0), (0, 1,0), (0, 0, I) and (1, I, 1) if
space is rotated by rr/4 radians about an axis (1,0, 1) + fJ.(3, 4, 5) .
Using the above theory we note that

F=
I °°° -1)
(oo °° ° °
0 I
1 -I
1
Matrix Representation of Transformations on Three-dimensional Space 151

G=!eaa aa a a
5
400)
3a a
5
G- 1 =.!.
5
C o
a 0 5 a
0)
4 -43 a a

5 a 0 a 5

~l 0
1 0../2 a
-1
n- 1 = _1 ( 0a 0)
0../2 1 0
H = -"';2 1 a 1
o a a vV ../2 -1 a 1
o a a
0
../2

~ j)
-1 a
1 a
and
W="/2 a a ../2

Cl
a a
-12 - 13y'2 -15 + 35-/2 -26 + 6v'2)
1 -12 + 9-/2 34 + 16../2 -20 + 5../2 32 - 42../2
+ 37../2
P» - -
50../2 -15 - 5../2 -20 + 35../2 25 + 25../2 -10 + 30../2
a o a 50../2

where P = p-l X G- 1 X H- 1 X W X H X G X F is the matrix representation of


the required transformation. Premultiplying the column vectors equivalent to
(0, 0 , 0), (1, 0, 0), (0, 1, 0), (0, 0, 1) and (1,1,1) by P and changing the resulting
column vectors back into row form and taking out a factor 1/50../2 gives the co-
ordinates (-;-26 + 6../2, 32 - 42../2, -10 + 30../2), (15 + 15../2,20 - 5../2,
- 25 +25../2),(-38 -7../2 ,66 -26../2,-30+65../2),(-41 +41../2, 12 - 37../2,
15 + 55../2) and (-12 + 37../2 , 34 + 16../2, -20 + 85../2) respectively. Naturally
translating and rotating space should leave relative positions unchanged; in
particular the angles between direction vectors should be unchanged (the same
cannot be said about the scaling transformation, which in general does alter
relative positions). In the original system the three relative positions from
(0 , 0, 0) to (1, 0, 0), (0, 1, 0) and (0, 0,1) respectively, are mutually perpen-
dicular (that is, the dot product of pairs of these directions should be zero) .
The dot product of the directions in the transformed system should also be zero :
the three directional vectors (with 1/50../2 factored out) are (41 + 9../2,
-12 + 37../2, -15 - 5../2), (-12 - 13../2,34 + 16../2, -20 + 35../2) and
(-15 + 35../2, -20 + 5../2, 25 + 25../2), and the dot product of any pair is zero.
Similarly the dot product of the direction vector from the origin to (1, 1, 1)
in the original system, taken with any of the original directions above, give the
same value (= 1). This is also true in the transformed system: the fourth direction
is (14 + 31../2, 2 + 58../2, -10 + 55../2), and when we take the dot product with
each of the three direction vectors above we get the value 5000, which, when we
take into account the factor (1/50../2)2 , gives the value 1.
A program that reads in the axis of rotation (PX, PY, PZ) + Jl(QX, QY, QZ)
152 Advanced Graphics with the Sinclair ZX Spectrum

and the angle GAMMA, and rotates any point (XX, YY, ZZ) about this axis by
angle GAMMA is given in listing 8.6.

Listing 8.6
100 REM rotation of a point about a given axis
110 DIM A(4,4): DIM BC4,4): DIM RC4,4)
120 DIM P(3): DIM AS(8)
130 INPUT ''BASE VECTOR OF AXIS ","C";PX;",";PY;",";PZ;")"
14l' PRINT AT 1,0; "BASE VECTOR OF AXIS ", "C";PX;",";PY;",";PZ;")"
150 INPUT "DIRECTION VECTOR OF AXIS ","C";QX;",";QY;",";QZ;")"
160 PRINT AT 4,0; "DIRECTION VECTOR OF AXIS ","C";QX;",";QY;",";QZ; ")"
170 INPUT "ANGLE OF ROTATION ";GAMMA
180 PRINT AT 7 ,0;"ANGLE OF ROTATION " ; G A~l MA
190 LET R1Llt3 = 9100: LET idR3 = 9300: LET rct3 = 8600
: LET tran3 = =
9000: LET angle =
8800: LET genrot 5800
198 REM calculate RC4,4) for rotating point by angle GAMMA about an axis
199 REM with base vector CPX,PY,PZ) and di rection vector CQX,QY,QZ).
200 GO SUB idR3: GO SUB genrot
210 PRINT AT 14,0;"BECOMES"
219 REM input and transform point CXX,YY,ZZ).
220 INPUT "POINT VECTOR","C";XX;",";YY;",";ZZ;")"
230 PRINT AT 12,0;"POINT C";XX;",";YY;",";ZZ; ")""
24l' LET P(1) :, XX*R(1,1) + YY*R(1,2) + ZZ*RC1,3) + RC1,4)
250 LET P(2) = XX*RC2,1) + YY*RC2,2) + ZZ*R(2,3) + R(2,4)
260 LET P(3) = XX*RC3,1) + YY*RC3,2) + ZZ*RC3,3) + RC3,4)
269 REM tidy up o utput.
270 PRINT AT 16, 0 ; " C" ;
280 FOR I= =
1 TO 3: LET AS =
STRS PCI): FOR J 1 TO 8
290 IF ASCJ) <> " " THEN PRINT ASCJ);
300 NEXT J: IF I <> 3 THEN PRINT ", ";
310 NEXT I: PRINT ")""
320 GO TO 220

Exercise 8.1
Experiment with these ideas. You can always make a check on your final trans-
formation matrix by considering simple values as above , and you can use the
previous listings to check your answer. It is essential that you are confident in
the use of matrices, and the best way to get this confidence is to experiment. You
will make lots of arithmetic errors initially, but you will soon come to think of
transformations in terms of their matrix representation, and this will greatly ease
the study of drawing three-dimensional objects.

Exercise 8.2
As with the two-dimensional case, we note that the 'bottom row' of all trans-
formation matrices is always (0, 0, 0, 1), and is of no real use in calculations. It
is added only to form square matrices, which are necessary for the formal
definition of matrix multiplication. We can adjust this definition , and that of the
multiplication of a matrix and a column vector, so that instead we use only the
top three rows of the 4 X 4 matrices (in chapter 4 we used the top two rows of
3 X 3 matrices in listings 4.2a, 4.3a, 4.4a and 4.5a). Change listings 8.1,8 .2,8.3
and 8.4 accordingly.
Matrix Representation of Transformations on Three-dimensional Space 153

Exercise 8.3
You will have noticed that the routine 'rot3' is usually called with THETA
generated by 'angle', which uses values AX and AY as input parameters. 'rot3'
calculates the cosine and sine of angle THETA, but we know that these are
AX/y(AX 2 + Ay 2 ) and AY/y(AX 2 + Ay 2 ) respectively. Write another
rotation routine 'rotxy' that calculates the rotation matrix directly from AX
and AY without resorting to 'angle'.
Also we note that the first stage of the 'rot', 'tran', 'scale' and 'idR' routines
consists of clearing an array . This can be achieved more efficiently on the
Spectrum by reDIMensioning the array. Furthermore it is often faster to ex-
plicitly assign values rather than calculate them inside FOR...NEXT loops.

Exercise 8.4
Again in chapter 4 we noted that some writers use row rather than column
vectors, and postmultiply rather than premultiply . We decided against this inter-
pretation, so that the matrix of a transformation corresponds directly with the
coefficients of the transformation equations . In this other interpretation it is the
transpose of the matrix that is identical to the coefficients. It is useful to be
aware of this other method, so use it to rewrite all the programs given in this
chapter (and the remainder of this book) . Remember though, it is not important
which method you finally decide to use, as long as you are consistent. We use
the column vector notation because we have found that it causes less confusion
in the early stages of learning the subject!

Compie Programs

I. All the listings in this chapter, 8.1 ('mult3' and 'idR3'), 8.2 ('tran3'), 8.3
('scale3'), 8.4 ('rot3'), 8.5 ('genrot'), 8.6 (main program) and listing 3.4
('angle'). Required data: base vector (PX, PY, PZ), direction vector (QX, QY,
QZ) of the axis of rotation and the angle GAMMA, together with any number
of three-dimensional coordinates (XX, YY,ZZ). Try (0, 0, 0),(1,1,1) and
rr/4, and points (1,0, 1), (1, 1, 1), (1,2,3).
9 Orthographic Projections

Wemay now address the problem of drawing views of three-dimensional objects


on our (necessarily) two-dimensional graphics screen . The simple method we
describe here is a direct generalisation of the -method introduced in chapter 4 for
two-dimensional objects . Again it involves the use of (up to) three positions. To
illustrate these ideas we first give a brief outline, and then expand on this using
numerous pictorial and numerical examples . We start by defining an arbitrary but
fixed triad of axes in space that we call the ABSOLUTE system. Then, as in the
two-dimensional case, we consider three positions : (1) the SETUP, (2) the
ACTUAL and (3) the OBSERVED position .

(1) The SETUP Position

Most scenes will be composed of simple objects (for example , cube(s), see ex-
ample 9.1) that are set at a peculiar position and orientation in space. It is very
inefficient to calculate by hand the complicated coordinates of every vertex of
these objects and input them into the program. Instead we look at each object in
turn and initially defme it in an elementary way relative to the ABSOLUTE triad ,
usually setting it about the origin. The information required will be that of
vertices (x-coordinate,y-coordinate and z-coordinate), and perhaps lines (that
join pairs of vertices) or (later when we consider hidden line and hidden surface
algorithms) facets, which are polygonal planar areas bounded by the above-
mentioned lines. This elementary definition of the object is called its SETUP
position. We could have other information also, such as the colour of the object.

(2) The ACTUAL position

We use the matrix techniques of the last chapter to generate a matrix that will
move the object from its SETUP position to its required ACTUAL position
relative to the ABSOLUTE axes. We shall call this SETUP to ACTUAL matrixP.
Orthographic Projections 155

(3) The OBSERVED Position

Viewing an object in three-dimensional space naturally involves an observer (the


eye - and note only one eye!) placed at a position (EX, EY, EZ) relative to the
ABSOLUTE axes looking in a fixed direction : this direction of view can be
uniquely determined by any other point on the line of sight, (DX, DY, DZ) say.
The head can also be tilted, but more of that later. What the eye sees when look-
ing at a three-dimensional object is a projection of the vertices, lines (and facets)
of the object on to a (two-dimensional) view plane that is normal to the line of
sight. In order to calculate such projections we must standardise our approach.
We use matrix methods to transform all the points in space so that the eye is
placed at the origin, and the line of sight is along the positive z-axis. This is the
OBSERVED position, and the matrix that transforms the ACTUAL to OBSERV·
ED position is called Q throughout this book. The method for calculating Q will
be dealt with in detail later, but for the time being we assume that the eye is
already at the origin looking along the a-axis: so in this simple case Q is the
identity matrix.
When all the points in space have been moved into this OBSERVED position,
we note that the view plane is now parallel to the x/y plane through the origin.
Having moved the eye into the correct position, we are now ready to project the
object on to the view plane. But note, as yet we have neither defined the position
of the view plane (we have only its normal), nor have we described the type of
projection of three-dimensional space on to the plane. These two requirements
are closely related. In this book we shall consider two possible projections: in a
later chapter we shall deal with the perspective projection, but first we introduce
the simplest projection, the orthographic.

The Orthographic Projection

Nothing could be simpler. In the orthographic projection we can set the view
plane to be any plane with normal vector along the line of sight. When trans-
formed into the OBSERVED position, the view plane will be any plane parallel
to the xly plane given by the equation z = O. For simplicity we take the x/y
plane through the origin. The vertices of the object are projected on to the view
plane by the simple expedient of setting their z-coordinates to zero . Thus any
two different points in the OBSERVED position, (x, y, z) and (x, y, z') say
(where z =1= z'), are projected on to the same point (x,y, 0) on the view plane .
Then we identify the xfy values on the plane with points in the graphics screen
coordinate system (usually centred on the screen) using the methods of chapter
2 . Once the vertices have been projected on to the view plane and then on to the
screen, we can construct the projection of lines and facets. These are related to
the projected vertices in exactly the same way as the original lines and facets are
related to the original vertices.
156 Advanced Graphics with the Sinclair ZX Spectrum

Before considering in detail the general case where the eye and direction of
view are arbitrarily positioned, we take an elementary example to demonstrate
the orthographic projection.

Example 9.1
Use the above ideas to draw an orthographic projection of a cube . Figures such
as those in figure 9.1 are called wire diagrams or skeletons (for obvious reasons) .
In the SETUP position the cube may be thought to consist of eight vertices
(1,1,1),(1,1 ,-1),(1 ,-1,-1),(1,-1,1),(-1,1 , 1),(-1, 1,-1),(-1 ,-1,-1)
and (-1, -1, 1): vertices labelled numerically 1 to 8. The twelve lines that form
the wire cube join vertices 1 to 2,2 to 3,3 to 4 , 4 to 1; 5 to 6,6 to 7, 7 to 8,
8 to 1; 1 to 5, 2 to 6, 3 to 7,4 to 8.
Figure 9.1 a shows the simplest possible example of an orthographic projec-
tion of the cube, where even the SETUP to ACTUAL matrix is the identity
matrix ; that is, the cube stays in its SETUP position. We get a square: pairs of
parallel lines from the front and back of the cube project into the same line on
the screen. We put a "+" in these diagrams to show the position of the z-axis in
the OBSERVED position (into the screen).
Figure 9.1b shows the same cube drawn after the following three transforma-
tions place it in its ACTUAL position .

(a) Rotate the cube by an angle a: = -0.927295218 radian about the z-axis -
matrix A . This example is contrived so that cos a: = 3/5 and sin a: = -4/5 ,
ensuring that the rotation matrices consist of uncomplicated elements.
(b) Translate by the vector (-1 , 0, 0) - matrixB.
(c) Rotate by an angle -a about the y -axis - matrix C.

The SETUP to ACTUAL matrix is thus P = C X B X A, where

0) (0o -1)oo
C C5
5 4/5 0 0 4/5
o
-4~5 3/5 o 0
D
B= 0 1 0 C= 0 1 0
A=
0 1 0 0 1 -4/5 0 3/5
0 o 1 o 0 0 1 0 0 0

and P is given by

p=~eo
12 20 -15)
15 0 0
25 -12 -16 15 20
0 o 0 25

So the above eight vertex coordinate triples in the SETUP position are trans-
formed into the following eight ACTUAL coordinate triples : (26/25, -5/25,
7/25), (-14/25, -5/25, -23/25), (-38/25, -35/25 , 9/25), (2/25, -35/25 ,
Orthographic Projections 157

39/25), (8/25, 35/25 , 31/25), (-32/25,35/25,1/25), (-56/25,5/25,33/25),


(-16/25,5/25 ,63/25).
For example (1,1,1) is transformed to (26/25 , - 5/25, 7/25) because

-1 ~9
-20 12 20
15 0 -15)
0 X (1
1 ) = - 1 (26)
-5
25 -12 -16 15 20 1 25 7
o 0 0 25 1 25

Since the ACTUAL to OBSERVED matrix Q is the identity matrix, the pro-
jected coordinates on the view plane are thus (26/25, -5/25), (-14/25, -5/25),
(-38/25 , - 35/25), (2/25, -35/25), (8/25 , 35/25), (-32/25,35/25), (-56/25,
5/25), (-16/25,5/25). We can place these points on the screen and join them
with lines in the same order as they were defined in the SETUP cube .

. J\
...
..... \\. ..."'"
...•.. .....•
,.,f

.'
\ .../ '
l ,·I'··
+ ~-----'I:"i

"\
" +
\ •..l '/ '
"
'\ .
.,./, ,'"
\ ., ,.,0'/
... \ .'
\ 01.... ..:,\,,/ "

(a) (b)

(c) (d)

Figure 9.1
158 Advanced Graphics with the Sinclair ZX Spectrum

Construction of the ACTUAL to OBSERVED Matrix Q

We assume that the eye is at (EX, EY, EZ) relative to the ABSOLUTE axes, look-
ing towards the point (DX, DY, DZ). The OBSERVED position is achieved in the
following sequence of steps .

(1) A matrix D translates all the points in space by a vector (-DX, -DY, -DZ)
so that now the eye is at (EX - DX, EY - DY, EZ - DZ) = (FX , FY, FZ) say,
looking towards the origin.

1 0 0 -DX)
D= 0 1 0 -DY
( o 0 1 -DZ
o0 0 1
(2) A matrix E changes (FX , FY, FZ) into (r, 0, FZ) by rotating space by an
angle -a where 0: = tan"! (FY/FX) about the z-axis, Here r 2 = FX 2 + Fy 2 and
r>O .

00)
~
FX FY
E= ~ -FY FX 0 0
rOO r 0
o 0 0 r
(3) A matrix Ftransforrns (r, 0, FZ) into (0,0, -s) by rotating space by an angle
rr - 8 about the y-axis , where 8 =tan -1 (r/FZ). Here S2 =r 2 + FZ 2 = FX 2 +
Fy2 + FZ 2 and s > O.

- FZ 0 r
F= ~ 0 s o
s ( -r 0 -FZ
o 0 o
(4) The transformation thus far places the eye at (0, 0, -s) on the negative z-
axis looking towards the origin and at the same distance from it (s) as (EX, EY,
EZ) was from (DX, DY, DZ). We now generate a matrix G, which moves the
eye to the origin.

G=
1 0
0 1
o
oo0
0 1 s
0)
(
o 0 o 1

(5) If in example 9.1, we now premu1tiply P = ex B X A by our rust approxi-


mation to the ACTUAL to OBSERVED matrix Q (= G X F X E X D) to find
Orthographic Projections 159

the SETUP to OBSERVED matrix R =Q X P =G X F X E X D X ex B X A,


we draw figure 9.1 c by orthographic projection. This view is not really satisfac-
tory because the matrix Q places the cube at an arbitrary orientation within the
view plane . It is much better to standardise our view, and one of the most
popular ways is to maintain the vertical , that is a line that was vertical (or paral-
lel to the y-axis) in its ACTUAL position remains vertical after transformation
by Q into its OBSERVED position. Take the vertical line from (DX, DY, DZ) to
(DX, DY + 1, DZ). Because of this peculiar construction, we note that inter-
mediate matrix K (F X E X D) transforms this line into one joining (0, 0, 0) to
(K(1 ,2), K(2 ,2), K(3 ,2» = (P. q. r), say. So if we further rotate about the a-axis
by an angle 13 = tan- 1 (K(l , 2)fK(2 , 2» =tan - 1 (p/q) =tan- 1 (-FY x FZf
(s x FX» using a matrixH, before multiplying by G, then the vertical is
maintained

H= ~(:
t 0
o
and thus

Thus the complete transformation (figure 9.1d) is achieved by the matrix


R = Q X P = G X H X F X E X D X C X B X A, and the projection of the line
joining points (DX, DY, DZ) to (DX, DY + 1, DZ) is the line joining (0, 0) to
(0, t) on the screen ; that is, the vertical. Matrix G does not affect the x/y values.
Note that this technique works in all cases except where (EX, EY, EZ) is vertically
above (DX, DY, DZ) to start with, and naturally maintaining the vertical makes
no sense. The routine '100k3' (listing 9.1), given (EX, EY, EZ) and (DX, DY,
DZ), generates the ACTUAL to OBSERVED matrix in the steps shown above,
and at each step premultiplies the matrix R : so at the end of the process, R will
hold its original matrix value premultiplied by Q. Ifwe wish to store Q explicitly,
then we need first to set R to the identity matrix (using 'idR3'), then call
'l00k3', and finally copy array R into array Q. Routine 'l00k3' can be radically
reduced if we assume that the eye always looks at the origin (that is, DX = DY =
DZ = 0). Furthermore with the orthographic projection the OBSERVED position
of the eye need not be at the origin , it merely needs to be on the z-axis: again
the routine can be cut down. We give the most general case, which will be
essential for later perspective projections.
160 Advanced Graphics with the Sinclair ZX Spectrum

Listing 9.1
820~ REM look3
821~ INPUT "(EX,EY,EZ) "; EX; ", "; EY; ", "; EZ
8220 INPUT "(OX,OY,OZ) ";OX;",";OY;", ";OZ
8229 REM move origin to (OX,OY,OZ).
8230 LET TX = OX: LET TY = OY: LET TZ = OZ
8240 GO SUB tran3: GO SUB mult3
8249 REM move eye onto negative z-axis, looking at the or igin.
8250 LET FX = EX - OX: LET FY = EY - OY: LET FZ = EZ - OZ
8260 LET AX = FX: LET AY = FY: GO SUB angle
827~ LET AXIS = 3: LET THETA = -THETA: GO SUB rot3: GO SUB mul t3
8280 LET AX = FZ: LET AY = SQR (FX*FX + FY*FY): GO SUB ang le
8290 LET AXIS = 2: LET THETA = PI - THETA: GO SUB rot3: GO SUB mult3
8299 REM maintain vertica l.
830~ LET TX = 0: LET TY = 0: LET TZ = SQR (FX*FX + FY*FY + FZ*FZ)
831~ LET AX = TZ*FX: LET AY= -FY*FZ: GO SUB angle
8320 LET AXIS = 3: GO SUB rot3: GO SUB mult3
8329 REM move eye to the origin: space is now in the OBSERVED position.
833~ GO SUB tran3: GO SUB mul t3
8340 RETURN

If required, we can extend this program to deal with the situation where the
head is tilted through an angle r from the vertical. This is achieved by further
rotating space by -r about the z-axis, Thus matrix H should then rotate about
the z-axis by an angle ~ - r.
The construction of the ACTUAL to OBSERVED matrix is obviously inde-
pendent of everything other than the position of the eye, line of sight and the
tilt of the head. So if we wish to view a series of objects from the same position,
we can store Q and use it repeatedly for placing each object.

How to Define an Object

It is now time to deal with the problem of representing objects to the computer.
There is no definite solution, it really depends on what is being drawn and how
it is projected. In this section we describe various ways of setting up a data-base
to hold the information necessary for drawing any given scene, but make no
comment on their usefulness. This is considered in the remainder of the book
where we give examples to illustrate the value of particular methods in different
situations. Weshall be using arrays to hold large sets of data, and so naturally
the amount of space given to arrays will depend on the amount of information
required for a scene: be sure that when you declare these arrays there is enough
space for all the information; if in doubt, overestimate your store requirements.
Vertices. We will always need to define vertices and other special reference
points in a scene, and these we store as x, y and z-coordinates in arrays X, Y and
Z respectively, assuming that if the total number is not known explicitly, then
this value is calculated as NOV. So there must be space for not less than NOV
values in each of the three arrays. These vertices may be in the SETUP, ACTUAL
or OBSERVED position, it depends on the context of the problem. There will
Orthographic Projections 161

also be situations (perspective in particular) when we need to store the xjy -co-
ordinates of the projections of these NOV vertices - in arrays V and W. Naturally
this is unnecessary in the case of an orthographic projection of points in the
OBSERVED position since we can use the values already stored in the X and Y
arrays . The choice of data-base really depends on the scene and type of projection.
Lines. We can store information on NOL (say) line segments in the two dimen-
sional integer array L. The Ith line is defined by the integer indices (between I
and NOV) of the two points at each end of the line - we store the indices in
L(I, I) and L(2 , I) . The true coordinate values of the two points at each end of
the line segment can be found from the X, Y and Z arrays.
Facets. A facet is a convex polygonal area on the surface of a three-dimensional
object, and can be defined in a number of ways. Most facets will be triangular or
quadrilateral, so we usually assume that no facet has greater than six sides to
minimise waste of store . The NOF facets can be defined in terms of the indices
of the vertices at their corners in array F ; F(I, J) is the index of the Ith vertex on
the Jth facet. Naturally if the facet is not hexagonal then some of the values are
garbage so we need to store array H, the number of vertices/edges on each facet.
We can also store C, the integer colour code (if any) for each facet; but be care-
ful, the Spectrum allows only two colours in anyone character block. Another
method is to store the facet in terms of the indices of the lines in the object in
array F, which would thus refer to array L; F(I, J) would now be the index of
the Ith line on the edge of the J th facet . There are many other methods for
representing these, and other elements of a three-dimensional object : choose the
one most suitable to your particular situation.

Construction Routines and the 'Building Block' Method

For any required object we define a construction routine that needs, as para-
meters, a matrix R to move vertices into position and any other information
about the size of the object (if the object is to be stored in the SETUP position
then naturally no matrix is needed). The routine can then define the vertices,
lines, facets or any other elements of the object, and use the matrix R to move
the vertices of the object into the required position. Depending on the context
of the program, the routine can then either draw the object, or extend a data-
base containing this information. We shall give examples of both methods.
We can construct a scene containing a number of similar objects (so the data
will be in either the ACTUAL or the OBSERVED position) . There is no need to
produce a new construction routine for each occurrence of the object, all we do
each time is calculate a new SETUP to ACTUAL matrix P, and enter it (for the
ACTUAL position) or Q X P (for the OBSERVED position) into the same
routine. Naturally we require one new routine for each different type of object.
The complete scene is achieved by the execution of a main program (listing
9.2), which declares all the subroutine labels, then prepares the graphics screen
162 Advanced Graphics with the Sinclair ZX Spectrum

using input values of HORIZ and VERT and finally calls a routine 'scene3' that
organises the objects in space and then draws them. The main program below
will be used in all the three-dimensional graphics programs that follow, so do
not alter it without very good reason .

Listing 9.2

100 REM main program


110 LET start = 9700: LET setorigin = 9600: LET moveto = 9500
: LET l i net o = 94110: LET cl i p = 84110
120 LET rot3 = 8600: LET angle = 8800: LET scale3 = 8900: LET tran3 = 9000
: LET mult3 = 9100: LET idR3 = 9300
130 LET scene3 = 6000: LET look3 = 8200
139 REM dimension and centre the graphics area.
1411 INPUT "HORIZ ",HORIZ,"VERT ",VERT
150 GO SUB start
160 LET XMOVE = HORIZ*0.5: LET YMOVE = VERT*0.5
170 GO SUB setorigin
179 REM set the scene.
180 GO SUB scene3
190 STOP

'scene3' declares all the arrays that are required for storing information about
a scene, together with matrices zl, B. R and (perhaps) Q for moving objects into
position. Any other subroutine labels unique to this scene are also declared. If
required the values of NOV and NOL (or NOF) are initialised, and these will be
updated in later construction routines. For each individual object (a 'block),
'scene3 ' must calculate a matrixP that moves this block into the ACTUAL
position , and then call the construction routine using the correct matrix R (per-
haps SETUP to ACTUAL or SETUP to OBSERVED). All the blocks finally
construct the fmished scene. Sometimes the drawing of the projection is done
inside the construction routine , or it can be elsewhere in other routines specifi-
cally designed for special forms of drawing (as in hidden line and hidden surface
pictures) : it depends on what is being drawn and what is required of the view. As
usual, because of the restriction of not passing array parameters into subroutines,
we do not normally explicitly generate P and Q, but rely instead on updating
matrixR . If we require the ACTUAL to OBSERVED matrix then this routine
calls '100k3'. Should we need to store Q then we must first call 'idR3', which
sets matrix R to the identity ; remember all matrix operations are done via
matrices A and R , using matrix B to hold intermediate values.
Always use the clipping version of 'lineto' in your programs. It is so easy to
choose values of HORIZ and VERT that are too small, with the result that part
of the object goes outside the graphics area . Without the 'clip ' routine the pro-
gram will fail. There is a positive reason, however , for making these values small :
it enables us to zoom in on a small area of a scene, drawing it very large, and all
the exterior lines will be clipped away.
Our first example of this method is listing 9.3, which is the 'scene3' routine
needed to construct a picture of a single cube as shown in figure 9.1 d. The scene
Orthographic Projections 163

can be viewed from any position with the vertical maintained. Wehave also a
construction routine 'cube' (listing 9.4) that generates the data for a cube with
sides oflength 2. It places the vertices, eight sets of coordinate triples, in arrays
X, Y and Z. There is no need to store the lines of the cube explicitly, we get the
information from a DATA statement and draw the lines straight away. The data
for figure 9.ld are HORIZ =6, VERT =4, (EX, EY, EZ) =(-2,2,2) and
(DX, DY, DZ) =(-1,0,0).

Listing 9.3
6000 REM scene3/e xampLe 9.1
6010 DIM X(8): DI~ Y(8): DIM z(e)
6020 DIM A(4,4): DIM B(4,4): DIM R(4,4)
6~ 3e LET cube = 6500
6039 REM caLcuLate the SETUP to ACTUAL matr ix R.
6040 GO SUB idR3
6~5~ LET THETA = -0.92729522: LET AXIS = 3: GO SUB rot3 : GO SUB muLt3
6060 LET TX = -1 : LET TY = 0: LET TZ = 0: GO SUB tran3: GO SUB muLt3
6070 LET THETA = -THETA: LET AXIS = 2: GO SUB rot3: GO SUB muLt3
6079 REM change R: premuLt ipLy i t by the ACTUAL to OBSfRVED matrix.
6080 GO SUB look3
6089 REM caLL construction rout irE draw the cube.
6090 GO SUB cube
6100 RETURN

Listing 9.4
6500 REM cube / Lines (not stored)
6501 REM IN R(3,3)
6510 DATA 1,1,1, 1,1,-1, 1,-1,-1, 1,-1,1, -1,1,1, -1,1,-1, -1,-1,-1, -1,-1,1
6520 DATP 1,2, 2,3, 3,4, 4,1, 5,6, 6,7,7,8, 8,5, 1,5 , 2,6, 3,7, 4,8
6530 RESTORE cube
6539 REr" ;r ,put SETUP vert ices of cube and mov e them i nt o OBSERVED POSITION.
6540 FOR I = 1 TO 8
6550 READ XX, YY, ZZ
6560 LET XCI) = XX*R (1,1) + YY*R(1,2 ) + ZZ*R(1,3) + R( 1,4)
6570 LET yell = XX*R(2, 1) + YY*R(2,2) + ZZ*R(2,3) + R(Z,4)
6580 LET Z(I) = XX*R(3,1) + YY*R(3,2 ) + ZZ*R(3,3) + R(3,4)
6590 NE XT I
6599 REr~ i nput Line i nf ormat i on : draw Lines by j oin ing pairs of vertices.
6600 FOR! = 1 TO 12
6610 READ L1,L2
6620 LET XPT = X(L1): LET YPT = Y(L1): GO SUB moveto
6630 LET XPT = X(L2) : LET YPT = Y(L2): GO SUB Lineto
664flJ NE XT I
6650 RETU ~rJ

We can have more than one cube in the scene. For example, if we rewrite
'scene3 ' as in listing 9.5, keeping all the other routines the same, we would get
figure 9.2. Note that the X, Y and Z values of the previous cube are overwritten
in the second call to 'cube'. Also, because we have the same ACTUAL to
OBSERVED matrix for both cubes (they have different SETUP to ACTUAL
matrices) we need to store Q so it can also be used for the second cube. Remem-
ber Q must premultiply the array P, which moves the second cube into the
ACTUAL position. The data for figure 9.2 are HORIZ = 9, VERT = 6, (EX, EY,
EZ) = (3, 2,1) and (DX, DY, DZ) = (0, 0, 0) .
164 Advanced Graphics with the Sinclair ZX Spectrum

Listing 9.5
6000 REM scene3/figure 9.2
6010 DIM X(8): DIM Y(8): DIM Z(8)
6020 DIM A(4,4): DIM B(4,4): DIM R(4,4): DIM Q(4,4)
6030 LET cube = 6500
6039 REM draw 1 ' st cube in OBSERVED posi ti on.
6040 GO SUB i dR3 : GO SUB look3
6050 GO SUB cube
6059 REM draw 2 'nd cube i n OBSERVED pos it i on.
6060 FOR I = 1 TO 4: FOR J = 1 TO 4
6070 LET ~(I, J)= R(I,J)
6080 NEXT J: NEXT I
6090 GO SUB i dR3
6100 LET TX = 3: LET TY = 1.5: LET TZ = 2: GO SUB t ran3: GO SUB mult3
6110 FOR I = 1 TO 4: FOR J = 1 TO 4
6120 LET A<I,J) = Q(I,J)
6130 NEXT J: NEXT I
6140 GO SUB mul t3
6150 GO SUB cube
6160 RETURN

/,~"/,,.'/]
/
"
./ /
l ....'
,.'

Figure 9.2

Exercise 9.1
Extend the routine 'cube' so that information about the size of a rectangular
block is input, enabling the routine to construct a block oflength LH, breadth
BH and height HT: multiply the x-values of the SETUP cube by LH/2, the y-
values by HT/2 and the z-values by BH/2.

Again it should be noted that the modular approach we have adopted may not
be the most efficient method of drawing three-dimensional pictures. We chose
this descriptive method in order to break down the complex situation into
manageable pieces. Once the reader has mastered these concepts, he should can-
nibalise our programs for the sake of efficiency. However, to show the value of
this modular approach we give another example, which illustrates just how
quickly programs can be altered to draw new scenes and situations.

Example 9.2
Wewish to view a fixed scene (for example, the one shown in figure 9.2) from a
variety of observation points.
In this case it is better to store the vertex coordinates of the scene in the
Orthographic Projections 165

ACTUAL position, rather than the OBSERVEDposition, and store the line
information in array L. The 'scene3' routine (listing 9.6) must first set NOV and
NOL to zero and then place the objects in their ACTUALposition using matrix
R =P. The construction routine 'cube' (listing 9.7) must therefore be altered to
update the data-base (but note the same routine could be used to store vertices
in their OBSERVED position, which needs only a different R = Q X P). Then
for each different view point and direction the 'scene3' routine must clear the
screen, set R to the identity matrix and call '100k3', and then call a special new
'drawit' routine (listing 9.8), which uses the matrix R (holding the values of Q,
the ACTUAL to OBSERVED matrix) to put the points in the OBSERVED
position and orthographically project them into arrays V and W (we cannot use
X and Y because this would corrupt our ACTUAL data-base). Routine 'drawit',
which was labelled in 'scene3', can then use the information in array L to draw
the picture on the screen.
Listing 9.6
6000 REM scene3/f igure 9.2 ( var i ety of vi ews )
6010 DIM X(16): DIM Y(16) : DIM Z(16)
6020 DIM V(16 ): DIM W(16): DIM L( 2,24)
6030 DIM A(4,4): DIM B(4,4): DIM R(4,4)
6040 LET cube = 6500: LET draw it = 7000
6050 LET NOV = 0: LET NOL = 0
6059 REM store 1 ' st cube in ACTUAL ( = SETUP) pos ition.
6060 GO SUB i dR3
6070 GO SUB cube
6079 REM st or e 2'nd cube i n ACTUAL pos it i on.
6080 LET TX = 3: LET TY = 1.5: LET TZ = 2: GO SUB tra n3: GO SUB mult3
6090 GO SUB cube
6099 REM loop through different viewing posi t ions.
6100 GO SUB i dR3 : GO SUB l ook3
6109 REM dr aw the two cubes in OBSERVED pos ition.
6110 CLS: GO SUB drawit
6120 GO TO 6100
6130 RETURN

Listing 9. 7
6500 REM cube/ vertices a nd l ine s (stored)
6501 REM IN NOV,NOL,X(NOV),Y (NOV),Z(NOV),L(2,NOL ),R (4,4)
6502 REM OUT: NOV,NOL,X (NOV),Y(NOV),Z(NOV),L (2,NOL )
6510 DATA 1,1,1, 1,1,-1, 1,-1,-1, 1,-1,1, -1,1,1, -1,1,-1, -1,-1,-1, -1,-1,1
6520 DATA 1,2, 2,3,3,4, 4,1, 5,6,6,7,7,8,8,5, 1,5, 2,6, 3,7, 4,8
6530 RESTORE cube
6540 LET NV = NOV
6549 REM i nput and store vertice s in posi t i on ( ACTUAL or OBSERVED ) us ing R.
6550 FOR I = 1 TO 8
6560 READ XX,YY,ZZ: LET NOV NOV + 1
6570 LET X( NOV) XX*R( 1, 1 ) + YY*R ( 1,2) + ZZ*R (1,3 ) + R(1,4 )
6580 LET Y(NOV) = XX*R(2,1) + YY*R( 2,2) + ZZ*R ( 2, 3) + R(2,4)
6590 LET Z(NOV) = XX*R(3,1 ) + YY*R(3,2 ) + ZZ*R( 3,3) + R(3,4)
6600 NEXT I
6609 REM i nput and store line i nf ormat ion.
6610 FOR I = 1 TO 12
6620 READ L1,L2: LET ~CL = NOL + 1
6630 LET L(1,NOL) = L1 + NV: LET L(2, NOL) = L2 + NV
6640 NEXT I
6650 RETURN
166 Advanced Graphics with the Sinclair ZX Spectrum

Listing 9.8
7000 REM drawit
7001 REM IN : NOV,NOL,X(NOV),Y(NOV),Z(NOV),L(2,NOL ),R(4,4 )
7~02 REM move vertices i nt o OBSERVED posit ion and draw object.
7010 FOR I =
1 TO NOV
7020 LET V(I) =
X(I)*R(1,1) + Y(I)*R(1,2) + Z(I)*R(1,3) + R(1, 4)
7030 LET we!) = X(I)*R(2,1) + Y(I)*R(2,2) + Z(!)*R(2,3) + R(2,4)
7040 NEXT I
7050 FOR ! =
1 TO NOL
7060 LET L1 = L(1,!): LET L2 = L(Z,J)
7~70 LET XPT = V(L1): LET YPT = W(L1): GO SUB mov et. o
7080 LET XPT = V(L2): LET YPT = W(L2): GO SUB lineto
7090 NEXT!
7100 RETURN

If the observer is travelling in a straight line and always looking in the same
direction, we need not even calculate Q each time, but simply initially manipulate
space so that the observer is looking along the a-axis, and then use the 'setorigin'
routine to move the observer instead! After you have gained expertise in drawing
three-dimensional projections, you should choose your construction and viewing
method with care. You will rarely need to go through the complete method given
in this chapter, there will always be short-cuts.

Exercise 9.2
Produce construction routines for a tetrahedron, pyramid, etc. For example,
(a) tetrahedron: vertices (1,1, 1), (1, -1, -1), (-1, 1, -1) and (-1, - 1, 1);
lines 1 to 2,1 to 3,1 to 4 , 2 to 3,2 to 4 and 3 to 4.
(b) pyramid with square of side 1 and height HT: vertices (0, HT, 0),(1, 0,1),
(1,0, -1), (-1,0, -1) and (-1 ,0, 1); lines 1 to 2 , 1 to 3, 1 to 4, 1 to 5, 2 to 3,
3 to 4, 4 to 5 and 5 to 1.

Exercise 9.3
Set up a line drawing of any planar object in the x/y plane; for example, the out-
line of an alphabetic character or string of characters, and view them in various
orientations in three-dimensional space. You can place such planar objects on the
side of a cube . All you need do is extend the 'cube' routine above to include extra
vertices and lines that define the symbols.

Thus far we have restricted our pictures to those of the simple cube. This is so
that the methods we give are not obscured by the complexity in .defining objects.
Our programs will work for any object provided it fits within the limitations of
our store (and time). For complex objects we merely extend the size of our
arrays, although some objects will have properties that enable us to minimise
store requirements. Consider the jet shown in figure 9.3 - it possesses two-fold
symmetry, which can be used to our advantage . We assume that the plane of
symmetry is the y/z plane, and so for every point (x, y, z) on the jet there is also
a corresponding point (-x, y, z). To draw figure 9.3 we use listings 9.1,9.2 and
Orthographic Projections 167

9.3 , together with a construction routine 'jet' that generates all the vertices of
the aeroplane with positive x-coordinates; thus information about only one-half
of the jet is stored. To construct the complete aeroplane we need also a 'drawit'
routine (listing 9.9), which draws one side of the jet, and then, by reversing the
signs of all the x -values, draws the other.

Figure 9.3
It is simple to construct these figures. Just plan your object in various sections
on a piece of graph paper, number the important vertices and note which pairs
of vertices are joined by lines. The coordinates values can be read directly from
the grid on the paper. The data for figure 9.3 are HORIZ = 160, VERT = 120,
(EX, EY, EZ) =(1,2,3) and (DX, DY, DZ) =(0, 0, 0) .

Bodies of Revolution

This far in our construction of objects we have relied on DATA to input all the

Figure 9.4
168 Advanced Graphics with the Sinclair ZX Spectrum

Listing 9.9
6000 RE M sce ne3! jet
6010 DIM X(37): DIM Y(37) : DIM Z(37)
6~20 DIM L( 2,46): DIM V(37): DIM W(37)
6030 DIM A(4,4): DIM B(4,4): DIM R(4,4)
604~ LET jet = 6500: LET drawit =7000
6050 GO SUB idR3 : GO SUB look3
6060 GO SUB jet
6070 GO SUB d r a ~i t
6080 RETURN
65~0 REM jet
6502 REM OUT: NOV,NOL,X(NOV),Y(NOV),Z(NOV),L(2,NOL)
6510 DATA 0,0,80, 0,~,64, 0,8,32, 4,8,32
6520 DAT A 8,4,32, 8,~,32, 4,-4,32
6530 DATA 0,8,-32, 4,8,-32, 8,4,-32, 8,~,-32
654~ DATA 4,-4,-32, 0,-4,-32, 8,~,24, 48,0,-32
6550 DATA 8,2,-32, 0,8,0, 2,8,-32, 0,32,-32
6560 DATA 28,-4,-24, 30,-2,-24, 32,-2,-24, 34,-4,-24
6570 DATA 32,-6,-24, 30,-6,-24, 28,-4,8 30,-2,8
6580 DATA 32,-2,8, 34,-4,8, 32,-6,8, 30,-6,8
659~ DATA 31,0,-24, 31,-2,-24, 31,-2,-12, 31,0,-12
6600 DATA 0,6,4~, 3,6,4~
6610 DATA 1,2, 2,3, 2,4, 2,5, 2,6, 2,7, 3,4
6620 DATA 4,9, 5,HI, 6,11, 7,12, 8,9, 9,HI, 10,11, 11,12
6630 DATA 12,13, 14,15, 15,10, 15,16, 14,16, 17,18, 17,19, 18,19
66~ DATA 20,21, 21,22, 22,23, 23,24, 24,25, 25,20, 26,27, 27,28
665~ DATA 28,29, 29,30, 30,31, 31,26, 20,26, 21,27, 22,28, 23,29
6660 DATA 24,30, 25,31; 32,33, 33,34, 34,35, 35,32, 36,37
6663 REM SETUP ver t ex and l ine i nf ormat i on for half the j et .
6700 LET NOV = 37: LET NOL = 46
6710 FOR I = 1 TO NOV: READ X(I),Y(I),Z(I): NEXT I
6720 FOR I = 1 TO NOL: READ L(1,I),L(2,I): NEXT I
6730 RETURN
7000 REM drawit! two halves of the jet
7001 REM IN : NOV,NOL,X(NOV),Y(NOV),Z(NOV),L(2,NOL),R(4,4)
7010 LET IS = 1
7019 REM loop through two halves of t he jet.
7020 FOR J = 1 TO 2
7030 FOR I = 1 TO NOV
704~ LET XX = IS*X(I): LET YY = Y(I): LET ZZ = Z(I)
7~49 REM put vert ices i n OBSERVED position.
7050 LET V(I) = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
7060 LET WeI) = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
7070 NEXT I
7080 FOR I = 1 TO NOL
7090 LET L1 = L(1,I): LET L2 = L(2,I)
7100 LET XPT = V(L1): LET YPT = W(L1): GO SUB moveto
7110 LET XPT = V(L2): LET YPT = W(L2): GO SUB lineto
7120 NEXT I
7130 LET IS = -1
71 4~ NEXT J
7150 RETURN

information about lines and vertices. We consider now a type of object where
only a small amount of information is required for a quite complex object -this
is a body of revolution, an example of which is shown in figure 9.4.
Orthographic Projections 169

The method is simply to create a defining sequence of NUMV lines in the x/y
plane through the origin ; we call this the definition set. Then we revolve this set
about the vertical (y-axis) NUMH-1 further times to create new vertical sets.
The NUMV lines in the definition set are formed by joining the NUMV + 1
vertices (S(I), T(I), 0) (where I ~ I ~ NUMV + 1) in order. From this we generate
NUMH different vertical sets, the J t h vertical set is the definition set rotated
through an angle PHI + 21T(J - l)/NUMH about the vertical y-axis, for some in-
put value PHI (fjJ) . As well as the set of NUMH x NUMV vertical lines we intro -
duce horizontal lines also. We consider a single point (S(I), T(I), 0) at the end of
a line segment in the definition set: as we rotate about the vertical axis it moves
into NUMH positions (provided that the point is not on the axis of rotation)

(S(I) x cos (0 + fjJ) , T(I) , S(I) x sin (0 + fjJ))

where 0 =21T(J - 1) with I ~ J ~ NUMH.


These NUMH points are joined in order and the NUMHth position is joined
back to the first, to give the It h horizontal set . So there are (NUMH - n) x
NUMV horizontal lines , where n is the number of vertices on the axis of rotation.
Listing 9.10 is a construction routine 'rotbod', which draws the body of revolu-
tion when given NUMV, NUMH, PHI, the original set of vertices in T and S, and
the positional matrixR . Listing 9.11 is the 'scene3' routine, which creates the
scene of a spheroid in figure 9.4 by placing eight points from a semicircle into
the definition set : HORIZ =3 .2, VERT =2.2 , PHI =1Tj25, NUMH = 10,
NUMV = 8, viewed from (1 ,2,3) looking at (0 , 0, 0) . NUMV is assumed to be
less than or equal to fifteen in listing 9.11 .

Listing 9.10
60~~ REM s cene3/ s phe r oi d
6~10 DIM X(32) : DIM Y(32)
6020 DIM A(4,4): DIM B(4,4): DIM R<4,4)
6030 DIM 5(16): DIM T(16)
6040 LET revbod = 650~
6050 INPUT "NUM3ER OF HORIZONTAL LINES",NUMH
6060 INPUT "NUM3ER OF VERTICAL LINES",NUMII
6070 INPUT "ANGLE PHI " ; PHI
6080 LET THETA = PI/2 : LEI TD = Pl/NUMII
6089 REM generate def inition set.
6090 FOR I = 1 TO NUMII + 1
610~ LET 5(1) = COS THETA: LET T<I) = SIN THETA
611~ LET THETA = THETA + TD
6120 NEXT I
6130 GO SUB idR3: GO SUB Look3
6140 GO SUB revbod
6150 RETURN

Exercise 9.4
Experiment with this technique, any line sequence will do . Try an ellipsoid : this
is essentially the same as the spheroid except that the definition set is produced
170 Advanced Graphics with the Sinclair ZX Spectrum

Listing 9.11
650~ REM revbodl body of revoLut ion
6501 REM IN : PHI,NUMH,NUMV,S(NUMV+1>,HMJMV+1>,R(4,4)
6509 REM create f irst verticaL set.
6511' LET THETA = PHI: LET TO = PI*2/NUMH
6520 LET N1 = NUMV + 1: LET C = COS PHI: LET S =SIN PHI
6530 FOR 1 = 1 TO N1
6540 LET XX = S(I)*C: LET YY = T(I): LET ZZ = S(I)*S
6550 LET XCI) = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6560 LET Y(I) = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
6570 NEXT J
6579 REM Loop through second ver ti ca L set~
6580 FOR J = 1 TO NUMH
6590 LET THETA = THETA + TO : LET C = COS THETA: LET S = SIN THETA
6601' FOR 1 = 1 TO N1
6610 LET XX = S(I)*C: LET YY = T(I): L ET ZZ = S(I)*S
6620 LET X(I + N1) = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6630 LET YO + N1) = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
6640 NEXT 1
6649 REM draw Lines i n first verticaL set.
6650 LET XPT = X(1): LET YPT = Y(1): GO SUB moveto
6660 FOR ! = 2 TO N1
6670 LET XPT = =
XCI) : LET YPT Y(I): GO SUB Lineto
6680 NEXT 1
6689 REM joi n corresponding horizontaL vertices on the two verticaL sets.
6690 FOR r = 1 TO N1
670~ LET XPT = XCI): LET YPT = Y(I) : GO SUB moveto
6710 LET XPT = X(I + N1) : LET YPT = YO + N1): GO SUB Lineto
6719 REM copy second verticaL set into first and repeat process.
6720 LET XCI) = XPT: LET Y(I) = YPT
6731' NEXT 1
674f1 NEXT J
6750 RETURN

from a semi-ellipse rather than a semicircle . There is no need to produce only


convex bodies : lines can cut one another, cross to and fro over the y-axis and
have x-values that move up and down.
This idea can be extended into a body ofrotation. Now as the set of lines
moves around the central axis, the y-values of the points do not stay fixed . They

Figure 9.5
Orthographic Projections 171

can move in a regular manner ; that is, drop by the same amount with each
rotation through 21T/NUMH. Now, of course, the lines can make more than one
complete rotation about the axis, see figure 9.5. Write a program to implement
a body of rotation.

Complete Programs

From now on we shall refer to listings 3.4 ('angle'), 8.1 ('mult3 ' and 'idR3 '),
8.2 ('tran3'), 8.3 ('scale3'), 8.4 ('rotJ'), 9.1 ('100k3') and 9.2 ('main program') as
'lib3' .

I. 'lib l ', 'lib3' and listings 9.3 ('scene3') and 9.4 ('cube'). Data required:
HORIZ, VERT, (EX, EY, EZ) and (DX, DY, DZ). Try 6,4, (1,2,3),
(-1,0 ,1).
II. 'lib1" 'lib3' and listings 9.5 ('scene3') and 9.4 ('cube'). Data required:
HORIZ, VERT, (EX , EY, EZ) and (DX, DY, DZ). Try 9,6, (1, 2, 3),
(-1,0,1). Make systematic changes to one of these input values and keep
all the other parameters fixed.
III. 'lib 1" 'lib3 ' and listings 9.6 ('scene3'), 9.7 ('cube') and 9.8 ('drawit'). Data
required : HORIZ, VERT , and then repeated input of (EX, EY, EZ) and
(DX, DY, DZ). Try 9,6, then (1,2,3), (-1,0, 1); (3,2,1), (0, 0,1). Again
make systematic changes to one of the input parameters.
IV. 'lib 1" 'lib3' and listing 9.9 ('scene3', 'jet' and 'drawit'). Data required:
HORIZ , VERT , and then repeated input of (EX, EY, EZ) and (DX, DY,
DZ). Try 160,120, then (I, 2, 31) , (-1,0,30); (3, 2,20), (0, 0, 21).
Again make systematic changes to one of the input parameters.
V. 'lib1" 'lib3' and listings 9.10 ('scene3') and 9.11 ('revbod'). Data required:
HORIZ, VERT , NUMH, NUMV (~15) , PHI, (EX, EY, EZ) and (DX, DY,
DZ). Try 3.2, 2.2,10,10, I, (I, 2, 3), (0, 0, 0); (3, 2,1), (0, 0, 0).
10 Simple Hidden Line and Surface
Algorithms

Having drawn a cube and other wire objects we soon become irritated by the lack
of solidity in the figures. We would like to consider solid objects, in which case
the facets at the front of the object will obviously restrict the view of the facets
(and boundary lines) at the back. In order to draw pictures of such objects we
have to introduce a hidden surface algorithm ; or a hidden line algorithm if we
wish to draw all, but only, the visible lines on the object. There are many, many
such algorithms - some elementary for specially restricted situations, others
very sophisticated for viewinggeneral complicated scenes. The time limitations
of microcomputers bar us from implementing the very complex algorithms . In
the case of the Spectrum we have also the limitation that we cannot draw more
than two colours in a character block , which therefore restricts us to line draw-
ings. Nevertheless, by limiting the types and number of objects in the scenes, it
is possible to get most acceptable pictures. In chapter 12 we discuss a relatively
complex algorithm , but here we consider two special types of scene - we use
the properties implicit in these special configurations to minimise the work
needed to discover which surfaces and lines are hidden. Later in this chapter we
shall give a simple method for drawing mathematically defined three-dimensional
surfaces, but to start we consider an algorithm for drawing a single solid convex
body in three -dimensional space.
For our work on hidden line and surface algorithms we choose to define a
scene by storing the NOV vertices of objects in the scene (in the OBSERVED
position) in arrays X, Y and Z as usual. However we shall now use facet informa-
tion rather than line. The NOF facets are stored in an array F (we need also the
array H for the number of edges on each polygonal facet), and to save space
insist that no polygonal facet has more than six edges. Should we need more
edges, then the facet must be broken down into a set of smaller polygons . In
order to make the hidden surface algorithm easier we impose a restriction on the
order of vertices within the array F. The vertices must be stored in the order in
which they occur around the edge of the facet, and when viewed from the out-
side of an object they must be in an anti-clockwise orientation. Naturally from
the inside the vertices taken in this same order would appear clockwise. We shall
assume also that all lines are the junction of two facets. Individual lines not
related to facets must be added as trivial two-sided facets .
Simple Hidden Line and Surface Algorithms 173

The Orientation of a Three-dimensional Triangle

Once we have planned our object in terms of vertices and facets , how do we
check that the facets are actually anti-clockwise? Simply write a program! The
orientation of any convex polygon can be calculated from any three of its ver-
tices taken in order, and so we need consider only an ordered triangle of vertices
from the facet. Wehave already seen, in chapter 7, a method for calculating the
orientation of a two-dimensional triangle. Our problem is solved if we can reduce
the three-dimensional situation to two dimensions.
For simplicity we assume that all objects are SETUP about and containing the
origin. We insist also that the infinite planes containing the facets on the surface
of an object do not pass through the origin. Then we rotate space so that one of
the vertices of the triangle in question lies on the negative z-axis (compare with
routine '100k3', listing 9.1). Since we assume the origin is inside the object and
the eye is outside, all we need do is project the transformed triangle back on to
the x/y plane (that is, ignore the a-coordinates) and treat it like a two-dirnen- .
sional triangle (in fact one of the three vertices will be (0,0)). Listing 10.1 is our
solution of the problem.

Listing 10.1

10~ REM orientation of a 3-D triang Le


110 DIM X(3): DIM Y(3): DIM Z(3)
120 DIM AC4,4): DIM BC4,4): DIM RC4,4)
130 LET rot3 = 860il: LET a nol e = s neil: LET muLt3 = 910il: LET idR3 = 930il
1~ LET J$ = "TYPE IN COORD INATES OF TRIANGLE "
150 FOR I = 1 TO 3
160 LET IS = "VERTEXC " t STR$ I + " ) =C"
17E INPUT CJ$ + I$);XCI);",";YCI);",";ZCI ); ")"
180 PRINT AT 2+2*I,0;I$; XCI); ", ";YCI);",";ZCI); ")"
190 NEXT I
199 REM f ind matr i x R that wiLL put CX(1),YC1),ZC1» on negat i vE z- axi s.
20il GO SUB i dR3
210 LET AX = X(1): LET AY = Y(1): GO SUB angLe
220 LET AXIS = 3: LET THETA = -THETA: GO SUB rot3: GO SUB muL t3
230 LET AX = Z(1): LET AY = SQR CX(1)*XC1) + Y(1)*YC1»: GO SUB angLe
2~ LET AXIS = 2: LET THETA = PI - THETA: GO SUB r ot 3 : GO SUB muLt3
249 REM transform triangLe so that aLL vertices Lie in an x /y pLane.
250 FOR I = 1 TO 3
260 LET XX = XCI): LET YY = YCI): LET ZZ = ZCI)
270 LET XCI) = XX*RC1,1) + YY*RC1,2)+ ZZ*RC1,3) + RC1,4)
280 LET YCI) = XX*RC2,1) + YY*RC2,2)+ ZZ*RC2,3) + RC2,4)
290 NEXT I
299 REM check i f the now 2-D triangLe i s cLockwise or ant i-cLoc kwise.
30il PRINT AT 11,0;"IF THE EYE AND THE ORIGIN ARE ON"
310 PRINT AT 13,0;"OPPOSITE SIDES OF THE FACET THEN"
320 PRINT AT 15,0;"THE TRIANGLE IS ";
330 LET DX1 = X(2) - X(1): LET CY1 = Y(2) - Y(1)
3~ LET DX2 = X(3) - X(2): LET DY2 = Y(3) - Y(2)
350 IF DX1*DY2 - DX2*D Y1 > 0 THEN PRINT "ANTI- ";
360 PRINT "CLOCKWISE. "
370 STOP
174 Advanced Graphics with the Sinclair ZX Spectrum

Exercise 10.1
Rewrite the wire-figure routines of the last chapter using the assumption that the
data are given as vertices and anti-clockwise polygonal facets , and not as lines.
Check your facet data with the above program . The line information is still there
of course, implicit in the facet data - they are the edges of the facet considered
as pairs of vertices. Within this information each line occurs twice, once on
each of two neighbouring facets . We do not want to waste time drawing lines
twice! Because of the anti-clockwise manner of constructing the figures we note
that if a line joins vertex I to vertex J on one facet then the equivalent line on
the neighbouring facet joins vertex J to I. So for wire figures stored as facets we
shall draw lines from vertex I to vertex J if and only if I < J .

A Hidden Surface Algorithm for a Single Closed Convex Body

A finite convex body is one in which any line segment joining two points inside
the body lies totally within the body : a direct extension of the definition in
two-dimensional space. It is automatically closed, and thus it is impossible to get
inside the body without crossing through its surface. We orthographically project
all the vertices of the object on to the view plane, noting that a projection of a
convex polygon with n sides in three-dimensional space is an n-sided convex
polygon (or degenerates to aline) in the view plane. Taking the projected ver-
tices of any facet in the same order as the original, we find that either the new
two-dimensional polygon is in anti-clockwise orientation, in which case we are
looking at the outside of the facet, or the new vertices are clockwise and we are
looking at the underside . Since the object is closed we are able to see only the
outside of facets ; the view of their underside is blocked by the bulk of the object.
Therefore we need draw only the anti-clockwise polygonal facets - a very simple
algorithm, which can be implemented in either construction or 'drawit' routines.
For example, an adjusted construction routine 'cube' for eliminating the
hidden lines from an orthographic picture of a cube is given as listing 10.2. Here
we do not store the facets , but instead READ the information from DATA and
draw the visible facets immediately. This program was used to produce figure
10.1, a hidden line version of figure 9.1d . We use all the routines from the last
chapter that were used to draw figure 9.1d, except of course.for the construction
routine that sets up the data as vertices and facets, and draws the object (this
replaces listing 9.4 in the program for drawing figure 9.1 d). Naturally we use the
same data that were used for figure 9.1 d.

Exercise 10.2
Change listing 10.2, so that it can draw a rectangular block oflength LH, breadth
BH and height HT, where LH, BH and HT are input parameters to the routine.
Then draw a hidden line picture of it. Draw hidden line pictures of tetrahedra,
pyramids, octahedra, etc. Add extra parameters to distort these figures so that
they are no longer regular, but are still convex.
Simple Hidden Line and Surface Algorithms 175

Listing 10.2
6500 REM cube/facets (not stored) hidde n l ine eLi mi nat i on
6501 REM IN : R(4,4)
65111l DATA 1,1,1, 1,1,-1, 1,-1,-1, 1,-1,1, -1,1,1, -1,1,-1, -1,-1,-1, -1,-1,1
6520 DATA 1,2,3,4, 5,8,7,6, 1,5,6,2, 2,6,7,3, 3,7,8,4, 4,8,5,1
65311l RESTORE cube
6539 REM pLace vertices in OBSERVED pos ition.
6540 FOR I = 1 TO 8
6550 READ XX,YY,ZZ
6560 LET X(l) = XX*RC1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6570 LeT Y(I) = XX*RC2,1) + YY*RC2,2) + ZZ*RC2,3) + R(2,4)
6580 NEXT I
6590 FOR I = 1 TO 6
6599 REM REA D fa cEt i nf 0rma t i on and draw i t if oriented anti-cL ockwise.
6600 READ F1,F2,F3,F4
661~ LET VX1 = XCF2)-X(F1): LET DY1 = Y(F2)-Y(F1)
66211l LET DX2 = XCF3)-X(F2): LET DY2 = YCF3)-Y(F2)
6630 IF DX1*DY2 - DX2*DY1 < 0 THEN GO TO 6690
6640 LET XPT = XCF1): LET YPT = YCF1): GO SUB moveto
6650 LET XPT XCF2): LET YPT = YCF2): GO SUB Lineto
6660 LET XPT XCF3) LET YPT YCF3 ): GO SUB Lineto
66711l LET XPT XCF4) LET YPT Y(F4): GO SUB Lineto
66811l LET XPT XCF1> LET YF'T Y<F1): GO SUB Lineto
6690 NEXT I
6711l1ll RETlif'to.

~\
\\
.
\ .
\

,\ "\
, I
"\ I
II 1I ~-' -" 1
.
, _~.~. I

I\ .I"~'
,
-" ' --
' _ _ ._~ .. ~ ~_~_r ..- - ""--

Figure 10.1

Bodies of Revolution

We can use this anti-clockwise versus clockwise method to produce hidden


surface pictures of the bodies of revolution that were defined in chapter 9. As
we go through the NUMH revolutions we generate NUMV facets with each move.
Provided these quadrilateral (or perhaps degenerate triangular) facets are care-
fully constructed in an anti-clockwise orientation, then we can use the same
algorithm. Listing 10.3 is just such a routine; it produces figure 10.2, a hidden
176 Advanced Graphics with the Sinclair ZX Spectrum

surface version of figure 9.4 (and uses the same input data). Again, because of
the modular design of our programs, all the routines needed to draw figure 10.2,
except 'revbod' , are the same as those given in chapter 9. Now, however , we
must deal solely with convex bodies of revolution.

Figure 10.2

As the routine rotates the definition set of lines about the vertical axis, it
stores the vertices of two consecutive vertical sets of lines. These form the
vertical edges of one slice of facets. The vertices on these facets are immediately
transformed by R (the SETUP to OBSERVED matrix) and stored in arrays X
and Y. In such a configuration of pairs of vertical lines the first set of vertices
have indices from 1 to NUMV + 1 (= Nl), and the second from Nl + 1 to 2*Nl.
The I th facet is bounded by four lines, two vertical joining vertex I to I + 1, and
1+ Nl to I + Nl + 1, and two horizontal joining I to I + Nl, and I + 1 to I + Nl
+ 1. Adjustments must be made if one of the original vertices is on the axis of
rotation , in which case the quadrilateral degenerates to a triangle. The order of
vertices in each facet is carefully chosen so that they are in anti-clockwise
orientation when viewed from outside the object. This allows us to use our
simple algorithm to draw the object with the hidden lines suppressed. This
technique was used also to draw figure I.1 in the introduction.

Exercise 10.3
Experiment with this technique . Any initial set of lines will do , provided that it
starts and ends on the vertical axis and the polygon thus formed in the x/y plane
is convex.
Simple Hidden Line and Surface Algorithms 177

Listing 10.3

6500 REM revbodl convex body of revolution (h idden line el imination)


6501 REM IN : PHI,NUMH,NUMV,S(MJMV+1),T<MJMV+1),R(4,4)
6510 LET THETA = PHI: LET TO = PI*2/NUMH
6520 LET N1 = NUMV + 1: LET C = COS PHI: LET 5 = SIN PHI
6529 REM create first vertical set.
6530 FOR I = 1 TO N1
6540 LET XX = S(I)*C: LET YY = T(I): LET ZZ = S(I)*S
6550 LET XCI) = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6560 LET Y(I) = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4 )
6570 NEXT I
6579 REM loop through second vertical set.
6580 FOR J = 1 TO NUMH
6590 LET THETA = THETA + TO: LET C = COS THETA: LET S = SIN THETA
6600 FOR I = 1 TO N1
6610 LET XX = S(I)*C : LET YY = T(I): LET ZZ = S(I)*S
6620 LET XCI + N1) = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6630 LET Y(I + N1) = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
6641il NEXT I
6649 REM take anticlockw ise triangle from each facet between the two sets.
If it keeps its orientation on projection then i t is visible.
6650 FOR I =1 TO NUMV
6660 LET F1 = I: LET F2 = 1+ 1: LET F3 ~ F2 + N1
6670 IF I = NUMV THEN LET F3 = F3 - 1
6680 LET Dx1 = X(F2) - X(F1) : LET OY1 = Y(F2) - Y(F1)
6690 LET DX2 = X(F3) - X(F2): LET OY2 = Y(F3) - Y(F2)
6700 IF OX1*O Y2 - OX2*OY1 < 0 THEN GO TO 6770
671II) LET F3 = F2 + N1 : LET F4 = F3 - 1
6720 LET XPT = X(F1): LET YPT = Y(F1): GO SUB moveto
6730 LET XPT = X(F2): LET YPT = Y(F2): GO SUB l i neto
6741il LET XPT = X(F3): LET YPT = Y(F3): GO SUB l ineto
6750 LET XPT = X(F4): LET YPT = Y(F4): GO SUB lineto
6760 LET XPT = X(F1): LET YPT = Y(F1): GO SUB lineto
6770 NE XT I
6779 REM copy se cond set into first and repeat process.
6780 FOR I = 1 TO N1
6790 LET XCI) = XU + N1): LET YO) = Y(I + N1)
6800 NEXT I
6810 NEXT J
6820 RETURN

Drawing a Special Three-dimensional Surface

The call for pictures of convex solids is limited, so we now look at one type of
non-convex figure that can be drawn using information about its special form.
We consider the construction of a restricted type of three-dimensional surface in
which the y-coordinate of each point on the surface is given by a single-valued
function of' of the x-coordinate and z-coordinate of that point; of' will be includ-
ed as a routine in the program - one such example is given in listing lOA, the
functiony = 4 x SIN (XZ)/XZ where XZ = V(x 2 + Z2) shown in figure 10.3 .
The data required were HORIZ =32, VERT =22, (EX, EY, EZ) =(3, 2, 1),
(DX, DY, DZ) = (0 , 0, 0) , NX = NZ = 16, XD = ZD = -10 and XT = ZT = 10.
178 Advanced Graphics with the Sinclair ZX Spectrum
Listing 10.4
6000 REM scene3
6010 DIM A(4,4): DI~ B(4,4): DIM R(4,4)
6020 LET surface = 6500: LET dra wlin = 7000: LET f 7200
6030 GO SUB i dR3 : GO SUB look3
6040 GO SUB surface
6050 RETU RN
6500 REM surface
6501 REM IN : R(4,4)
6510 DIM 0(256)
6520 INPUT "NX,XMI N,XMAX ";NX;",";XMI N;",";XMA X
6530 INPUT "NZ,ZMIN,ZMAX ";NZ;",";ZMIN;",";ZMAX
6540 LET XCI F = (XMA X - XMIN) / NX
6550 LET ZDIF = (Z~A X - ZMIN)/NZ
6559 REM draw zero'th set of fixed-x line s .
6560 LET XX = XMAX: LET ZZ = ZMIN: GO SUB f
6570 LET XA = XX*R(1,1> + YY*R(1,2) + ZZ*R(1,3) + F.< 1,4)
6580 LET YA = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
6590 FOR J = 1 TO NZ
6600 LET ZZ ZZ + ZDIF: GO SUB f
6610 LET XB = XX*R(1,1) + YY *R(1, 2) + ZZ*R(1,3) + R(1,4)
6620 LET YB = XX*R(2,1) + YY*R(2,2) + ZZ*R (2,3) + R(2,4)
6630 GO SUB draa l i n
6640 LET XA XB: LET ~A = YB
6650 NEXT J
66~ 9 REMdraw zero'th set of f ixed-z li nes.
6660 FOR J = 1 TO NX
6670 LET XX = XX-XDIF: GO SUB f
6680 LET XB = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + ~(1 , 4 )
6690 LET VB = XX*R(2, 1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
6700 GO SUB drawl in
6710 LET X ~ = XB: LET YA = YB
6720 NEXT J
6729 REM move x v a l u e ~ ta ck ;n NX s t eps .
6730 LET XS = XMAX
6740 FO R I = 1 TO NX
6748 REM draw vi si bl e parts of one f rom eac h of the f ixed-z li ne s :
6749 t he x values vary fr om (I-1 )st x- li ne to t he 1 ' t h.
6750 LET ZS = ZMA X
67 6 ~ FOR J = 1 TO NZ
6770 LET ZS = ZS - ZDIF
6780 LET XX = XS: LET ZZ = ZS : GO SUB f
6790 LET XA = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6800 LET YA = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
6810 LET XX = XS-XDIF: GO SUB f
6820 LET XB = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6830 LET YB = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
6840 GO SUB draw lin
6850 NEXT J
6859 REM draw visible parts of the fixed-x lines.
6860 LET ZZ ZMIN: GO SUB f
6870 LET XA = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6880 LET YA = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
6890 FOR J = 1 TO NZ
6900 LET ZZ = ZZ + ZDIF: GO SUB f
6910 LET XB = XX*R (1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6920 LET VB = XX* R(2, 1) + YY*R(2,2) + ZZ*R ( 2,3) + R(2,4)
6930 GO SUB drawl in
6940 LET XA = XB: LET YA = YB
6950 NEXT J
6960 LET XS = XS-X DIF
6970 NE XT r
(,c:l:ll RETU RN
Simple Hidden Line and Surface Algorithms 179

7000 REM drawLin/ draw L;ne between points


7001 REM IN : XA,YA,XB,YB,D(256)
7~08 REM visibLe parts of Line between (XA,YA) and (XB,YB).
7009 REM IA and IB are the x-pixeL posit ions of the two points.
7010 LET IA = FN X(XA): LET 18 = FN X(XB)
7~20 LET Y = VA: LET YD = 0
7 0 3 ~ IF IA <> IB THEN GO TO 7080
7039 REM if IA=IB then onLy draw Line if second point i s above f irst.
7040 PLOT IA,D(IA)
7050 LET IY = FN Y(YS)
,r60 IF IY > D(IA) THEN DRAW 0,IY - D(IA): LET D(IA) = IY
7070 RETURN
7079 REM move in pi xeL coLum ns from Left to right.
7080 LET YD = (YB - Y ~ } /(IB - IA)
7090 FOR K = IA TO IB
7100 LET IY = FN Y(Y)
7109 REM if y-p ixeL i s greater t han D, then reset D-vaLue.
7110 IF D(K) < IY THEN LET D(K) = IY
7120 LET Y = Y + YD
7130 NEXT K
7139 REM join aLL the points (I,D(I» where IA<=I<=IB.
7140 PLOT IA,D(IA)
7150 FOR K = IA + 1 TO IB
7160 DRAW 1,D( n -. C(K - 1)
7170 NEXT K
7180 RETURN
7200 REM f/ function to be drawn
7201 REM IN : XX,ZZ
7202 REI' OUT : YY
7210 LET YY = 4: LET XZ = SQR (XX*XX + ZZ*ZZ)
7220 IF XZ > 0.000001 THEN LET YY = 4*SIN (XZ)/XZ
7230 RETURN

Figure 10.3

Since it is impossible to draw every point on the surface, we have to approxi-


mate by considering a subset of these surface points. Wechoose those points with
xtz coordinate on a grid ; in other words when orthographically viewed directly
from above (thus ignoring the y-values), the points form a rectangular grid. This
grid is composed of NX by NZ rectangles in the x]z plane. The x-coordinates of
the vertices are equi-spaced and vary between XB and XT (XB < XT) and the
equi-spaced z-values vary between ZB and ZT (ZB < ZT). There are thus
180 Advanced Graphics with the SinclairZX Spectrum

(NX + 1) x (NZ + 1) vertices (X, Z) in the grid that can be identified by the pair
of integers (i , j)

X = XT + i(XB - XT)/NX 0 < i < NX


Z = ZT + j(ZB - ZT)/NZ 0 <j < NZ

The equivalent point on the surface is (X, Y, Z) where Y = [(X, Z) . Every one of
the (NX + 1) x (NZ + 1) points generated in this way is joined to its four
immediate neighbours along the grid (that is, those with an equal x-value or z-
value), unless it lies on the edge, in which case it is joined to three, or in the case
of corners to two, neighbours . The grid lines can be considered as NX + 1 sets of
different fixed-x line segments and NZ + 1 sets of fixed-z line segments . For
example the Ith fixed-x set of lines (0 < I < NX) consists of NZ lines joining pairs
of points equivalent to the grid points (I, J) to (I, J + 1), where 0 < J < NZ - 1.
The surface can undulate, so not all the lines need be visible from a given view
point. We devise a very simple method to eliminate the hidden lines by working
from the front of the picture to the back.
To simplify the algorithm we assume that the eye is always in the positive
quadrant (that is, EX > 0 and EZ > 0), and that the eye is always looking at the
origin (OX =DY =DZ =0). If the function is non-symmetrical and we wish to
view it from another quadrant, then we simply change the sign of x and/or z in
the function . We can then transform the surface into the OBSERVED position.
In this position we first orthographically project the front edge, the two grid
line with x = XT and z = ZT, on to the view plane. That is, the zeroth set of
fixed-x lines and the zeroth set of fixed z-lines, We now work from the front to
the back in NX steps. In the Ith step (1 < I < NX), we draw first the visible parts
of one line segment from each of the NZ fixed-a sets;the J th such line (1 < J <NZ)
joins the points equivalent to the grid points (I - 1, J) to (I, J) . That is, we join
the corresponding points on the (I - l)th fixed-x line to the Ith, starting at the
zeroth fixed-z line and working backwards. Then we draw the visible parts of the
Ith set of fixed-x line segments. This is all programmed in routine 'surface' .
As yet we have not explained how to draw the visible parts of the lines :
routine 'drawlin'. We define an array 0 of256 values, one for each column of
pixels across the screen . When we first draw the zeroth sets of fixed -x and
fixed-a lines, we put the pixel values of the points on these lines in the array D.
We calculate the row/column values for every pixel on a given line segment and
draw it if and only if the row value for a column is greater than the value stored
in D. Whenever a pixel is added to the diagram then the value of array 0 is
altered accordingly . This method furnishes us with a hidden line elimination
algorithm for mathematical surfaces because of the order in which we consider
the lines. If we move out of the positive quadrant, or let the scale of the figure
exceed the size of the graphics area, then we shall incur errors.
Simple Hidden Line and Surface Algorithms 181

Exercise 10.4
Change the functions 'f' used by this program. For example, use f= 4 x SIN(t)
where t = V(x 2 + Z2).

Exercise 10.5
The above program does not draw the underside of the surface if it shows below
the zeroth ftxed -x/z lines. Alter listing 1004 to correct this shortcoming . Defme
another array E(256) that initially holds information on the nearest edges, and
whenever pixels on the line segments go below the values stored in E then the :
pixel is drawn and the value of E altered. Can we use the same order for drawing
the lines?

Complete Programs

1. 'lib3 ' and listing 10.1. Data required : the vertex coordinates of a triangle
(X(I), Y(I), Z(I)), where 1 ~ I ~ 3. Try (1,0,1) , (1,1,0) and (0, I, 1):
also the same vertices in a different order (1, 1, 0) , (1, 0, 1) and (0, 1, 1).
II. 'lib 1" 'lib3' and listings 9.3 ('scene3') and 10.2 ('cube'). Data required :
HORIZ, VERT , (EX, EY, EZ), (DX, DY, DZ). Try 9, 6, (1,2,3), (0, 0, -1).
III . 'lib 1" 'lib3' and listings 9.10 ('scene3 ') and 10.3 ('revbod'). Data required :
HORIZ, VERT, NUMH, NUMV (~ 15), PHI, (EX, EY, EZ), (DX, DY, DZ).
Try 3.2,2 .2, 10, 10, 1, (1 ,2,3), (0, 0, -1).
IV. 'lib 1" 'lib3 ' and listing 1004 ('scene3 ', 'surface', 'draw lin' and 'f") . Data
required: HORIZ , VERT , (EX, EY, EZ), (DX, DY, DZ), NX, XB, XT, NZ,
ZB, ZT. Try 30,20, (1 , 2 , 3), (0 , 0, 0),16, -8 , 8,16, -8,8 .
11 Perspective Projections

We have seen that the orthographic projection has the property that parallel
lines in three-dimensional space are projected into parallel lines on the view
plane. Although very useful, such views do look odd! Our brains are used to the
perspective phenomenon of three-dimensional space, and so they attempt to
interpret orthographic figures as if they are perspective views. For example , the
cubes of figures 9.1 and 10.1 look distorted.
So it is essential to produce a projection that displays perspective phenomena
(that is, parallel lines should meet on the horizon); an object should appear
smaller as it moves away from the observer. The drawing-board methods devised
by artists over the centuries are of no value to us. Three-dimensional coordinate
geometry and the concept of ACTUAL to OBSERVED positions, however
furnish us with a relatively straightforward technique.

Figure 11.1
PerspectiveProjections 183

What is Perspective Vision?

To produce a perspective view we introduce a very simple definition of what we


mean by vision. We imagine every visible point in space sending out a ray that
enters the eye . Naturally the eye cannot see all of space, it is limited to a cone of
rays that fallon the retina, the so-called cone oi vision , which is outlined by the
dashed lines of figure 11.1 . The axis of this cone is called the straight-ahead ray.
We imagine that space has been transformed into the OBSERVED position with
the eye at the origin and the straight -ahead ray identified with the positive z-axis.
We place the view plane (which we call the perspective plane in this special
case) perpendicular to the axis of the cone of vision at a distance d from the eye.
In order to form the perspective projection we mark the points of intersection of
each ray with this plane. Since there are an infinity of such rays this appears to
be an impossible task. Actually the problem is not that great because we need
consider only those rays that emanate from the important points in the scene;
that is, the vertices at the ends of line segments or the corners of polygonal
facets . The final view is formed by relating the projected points on the perspec-
tive plane in exactly the same way as they are related in three-dimensional
space, and then identifying the view plane with the graphics screen.
Figure 11.1 shows a cube observed by an eye and projected on to two planes,
and the whole scene is drawn in perspective! two example rays are shown: the
first from. the eye to A, one of the near corners of the cube (relative to the eye),
and the second to B, one of the far corners of the cube. The perspective pro-
jections of these points on to the near plane are A' and B', and on to the far
plane A" and B". Note that the projections will have the same shape and
orientation, but they will be of different sizes.

Calculation of the Perspective Projection of a Point

We let the perspective plane be a distance d from the eye (variable PPD in
later programs). Consider a point P == (x,y, z) in space that sends a ray into the
eye. We must calculate the point where this line cuts the view plane (the z = d
plane); suppose it is the point P' == (x',y', d) . Let us first consider the value of
y' by referring to figure 11.2. By similar triangles we see that y'[d = ylz , that is
y' = Y x dfz : Similarly x' = x x dlz : Hence P' == (x x dlz , y x dfz , d) . Since the
view plane is identified with the x/y coordinate system of the graphics screen,
we can ignore the z = d coordinate.

Example 11.1
Calculate the perspective projection of a cube with eight vertices (0, 0, 4) +
(± 1, ± 1, ± 1) on the perspective plane z =4, where the eye is origin and the
straight-ahead ray is the positive a-axis.
The space is defined so that the scene is in the OBSERVED position. We can
184 Advanced Graphics with the Sinclair ZX Spectrum

- - - -- z -- - - -
p
p' - - I
y

---d---
Figure 11.2

calculate the projections of the eight vertices using the above method. For
example, (1, 1, 3) is projected to (I x 4/3,1 x 4/3,4)=(4/3,4/3,4)~(4/3,4/3)
on the screen. So we get the eight projections

(I, 1,3) ~(4/3,4/3) (I,-I,3) ~(4/3,-4/3)


(-1, I,3)~(-4/3,4/3) (-1, -1, 3) ~ (-4/3, -4/3)
(1,1,5) ~(4/5,4/5) (I, -I,5) ~(4/5, -4/5)
(-1,1 , 5) ~ (-4/5, 4/5) (-1, -1, 5) ~(-4/5, -4/5)

and the resulting diagram is shown in figure II .3a.

til til
.r-f •.-1
>< . ><
ro . (1j'
I'
I .
>,. >,:

.
x-a?,~:; , '8 ',,,,
~
. ~ . . x-axi s

(a) (b)
Figure 11.3

Properties of the Perspective Transformation

(1) The perspective transformation of a straight line (I' 3 say) is a straight line
(r2 say). This is obvious because the origin (the eye) and the line r 3 form a
plane (n say) in three-dimensional space and all the rays emanating from points
on r 3 lie in this plane. (If the line enters the eye, n degenerates into aline).
Naturally n cuts the perspective plane in a line r 2 (or degenerates to a point)
Perspective Projections 185

and so the perspective projection of a point on the original line r 3 now lies on
the new line r 2. It is important to realise that a line does not become curved on
perspective projection .
(2) The perspective transformation of a facet (a closed sequence of coplanar line
segments) is a facet in the perspective plane. If the facet is an area bounded by n
coplanar line segments, then the transform of this facet is naturally an area in the
Z = d plane bounded by the transforms of the n line segments. Again note that no
curves are introduced in this projection: if they were, then the task of producing
perspective pictures would be far more complicated.
(3) The projection of a convex facet is also convex. Suppose facet F I is project-
ed on to facet F2. Since the projection of a closed facet is also closed and lines
go into lines, then points inside F I are projected into points inside F2. Suppose
F 2 is not convex: then there exist two points PI andp2 inside F 2 such that the
line joining them goes outside this facet. Hence there is at least one point P on
the line outside F 2 . If PI and P2 are projections of points q I and q2 from F I,
then P is the projection of some point q on the line joining q I and q2 . Since the
F I is convex then q must be inside F I and thus P must be inside F2: a contra-
diction, and our proposition is proved.
(4) All infmitely long parallel lines appear to meet at one point, their so-called
vanishing point . If we take a general line (with base vector p) from a set of
parallel lines with direction vector h

where zh > 0; then the perspective transform of a general point on this line is

(
(Xp + IlXh) x ~, (yp + IlYh) x d)
(zp + IlZh) (zp + IlZh)

which can be rewritten as

(Xh + xplll) x d, (Yh +Yplll) x d)


( (Zh + zplll) (Zh + zplll)

As we move along the line towards large a-coordinates (that is, as Il ~ 00), then
the line moves towards its vanishing point, which is therefore given by
(d x Xh/Zh' d x Yh/Zh). This vanishing point is independent of P, the base point
of the line, and hence all lines parallel to the direction h have the same vanish-
ing point. Of course the case zh < 0 is ignored because the line would disappear
outside the cone of vision as Il ~ 00.
(5) The vanishing points of all lines in parallel planes are collinear. Suppose that
the set of parallel planes has a common normal direction n == (x n ,Yn, zn)' If a
general line in one of these planes has direction h == (Xh' Yh. zh), then h is per-
186 Advanced Graphics with the Sinclair ZX Spectrum

pendicular to n (all lines in these planes are perpendicular to the normal to the
plane n). Thusn • h = 0, which in coordinate form is

dividing by Zh gives

and so the vanishingpoint (d x Xh/Zh , d x Yh/Zh) lies on the straight line

xn X X +Yn X Y +d x zn = 0

and the statement is proved.

Example 11.2
Find the vanishing points of the edges of the cube in example 11.1, and of the
diagonals of its top and bottom planes.
We divide the twelve edges of the cube into three sets of four edges, each set
being parallel to the x-axis,y-axis and z-axis respectively and so with directional
vectors (1, 0, 0), (0, 1, 0) and (0, 0 , 1). The first two sets have zero Z -values, and
so their extended edges disappear outside the cone of vision and are ignored,
whereas the third direction has vanishing point (4 x 0/1 ,4 x 0/1) == (0, 0) on the
view plane. On the top and bottom faces the diagonals have directions (1,0, 1),
the major diagonal, and (-1 ,0, 1), the minor diagonal. The major diagonal on
the top plane is (-1 , 1,3) + 11(1 ,0, 1), and so the vanishing point is (4 x 1/1,
4 x 0/1) == (4 , 0). The minor diagonal on the top plane is (1 , 1,. 3) + Il( -1 ,0 , 1)
and the vanishing point is (4 x -1/1 , 4 x 0/1) == (-4, 0). By similiar calculations we
find that the vanishing points of the major and minor diagonals on the lower face
are also (4 , 0) and (-4 , 0) respectively. The relevant edges are extended to their
vanishingpoints in figure 11.3b. Note that all the lines mentioned lie in the two
parallel planes (the top and bottom faces of the cube) and so the vanishing points
should be collinear: since (4, 0), (0, 0) and (-4,0) all lie on the x-axis, this is
obviously true . It can be shown similarly that the vanishing points of the diagon-
als of the side faces lie on a vertical line through the origin.

Exercise 11.1
Draw a perspective view of a tetrahedron with vertices (1, 1,5), (1, - 1, 3),
(- 1, 1, 3) and (-1 , -1 , 5). Find the vanishing points (inside the cone of vision)
of lines that join pairs of mid-points of edges of the tetrahedron.
Perspective Projections 187

Programming the Perspective Transformation

The main program for drawing a perspective view of any scene is the same as
that for the orthographic view, namely listing 9.2. Again the overall scene is
created by a call to a routine 'scene3' similar to those discussed in chapter 9. We
shall often need to calculate explicitly the ACTUAL to OBSERVED matrix , so
that the eye is in the OBSERVED position at the origin looking along the positive
z-axis. This is achieved by routine '100k3', given in chapter 9 (listing 9.1) . Calls
are made to construction routines, each having a matrix R as parameter. Finally
the figure must be drawn, inside the construction routines or in a 'drawit'
routine .
The only difference between the program that draws a perspective view and
the program of chapter 9 (orthographic view) is in the calculation of the co-
ordinates of the projected image on the view plane. Unlike the orthographic, in
the perspective projection the coordinates on the view plane cannot be identified
with the x-value and y-value of the point in the OBSERVED position. We need
to store the perspective transformation of the vertices in the arrays V and W: the
Ithvertex (X(I), Y(I), Z(I)) in the OBSERVED position is projected to (V(I),
W(I)). The values in arrays V and W are given by

V(I) =X(I)*PPDjZ(I) and W(I) =Y(I)*PPDjZ(I) for I = 1,2, . . ., NOV

where the value of PPD is set to 3*VERT ; the reason for this equation is given in
the next section. The calculation of V and W can be made in the construction
routine in the 'scene3' or 'drawit' routines; this simply depends on the scene
being considered .

Example 11.3
We draw a flxed scene (the two cubes described in example 9 .2) in perspective
from a variety of observation points, setting HORIZ = 9 and VERT = 6. The
necessary 'scene3' routine is given in listing 11.1 below; note that this calculates
PPD (compare with listing 9 .6). This listing places the group of cubes in their
ACTUAL position using the 'cube' routine of listing 9.7, and then loops through
a number of different OBSERVER positions. For each time through the loop we
call '100k3' , which requires (EX , EY, EZ) and (DX, DY, DZ) to calculate the
ACTUAL to OBSERVER matrix. Then the perspective 'drawit' routine (listing
11.2) is called. This uses the matrix to transform the vertices from their (stored)
ACTUAL position to the OBSERVER position, and places the projected vertex
coordinates in arrays V and W, according to the above equations. The routine
can then finally draw the edges of the cubes in perspective.
Figure 11.4 was drawn using (EX, EY, EZ) == (15 ,10,5) and (DX, DY, DZ) ==
(0,0,0). Compare this with the orthographic view of the same scene given in
figure 9.2.
188 Advanced Graphics with the Sinclair ZX Spectrum

Listing 11.1
6000 REM scene3/figure 9.2 (variety of vi ews)
6010 DIM X(16): DIM Y(16): DIM Z(16)
6020 DIM V(16): DIM W(16): DIM L(2,24)
6030 DIM A(4,4): DIM B(4,4): DIM R(4,4)
6040 LET cube = 650V!: l.rT cr av t t = 7000
6050 LET PPD = 3*VERT: LF.T nov = 0: LET NOL = 0
6059 REM pLace two cubes in ACTUAL position.
6060 GO SUB idR3
6070 GO SUE' C'"re,
6080 LET TX = 3: LET TV = 1.5 : LET rz = 2: GO SUB tran3: GO SUB muLt3
6090 GO SUB cube
6099 RE~ Loop through variety of views.
6100 GO SUB idR3 : GC HB Look3
6110 CLS : GO SUB drawit
6120 GO TO 6Hl0
6130 RETURN

Listing 11.2
7000 REM drawitf perspect ive
7001 REf', III : f'F'(', NOV, NOL,XCNOV) ,Y(NOV) ,ZCNOV) ,LCt',NOU,R(4,4)
7009 REM put vert ices in OBSERVED position.
7010 FOR I = 1 TO NOV
7020 LET XX = X(I )*~(',1) + Y(I)*R(1,2) + Z(I)*R(1,3) + R(1,4)
7030 LET YY = X(I)*R(2,1) + Y(I)*R(2,2) + 2(I)*R(2,3) + R(2,4)
7040 LET ZZ = X(I)*R(3,1) + Y(I )*~( ~,2) + Z(I)*R(3,3) + R(3,4)
7049 REM per spectt ve proj ecti on.
7050 LET V(I) = xX*PPD/ZZ
7060 LET Wei) = YY*PPD/ZZ
7070 NEXT I
7079 R~r·: ,.'r'aW l ines.
7080 FOR I = 1 TO NOL
7090 LET i.t = L<1,I): LET L2 = U2,n
7100 LET XPT = V(L1 ): LFT ~PT = W(L1): GO SUB moveto
7110 LET XPT = V(LZ ): l r: YfT = W(L2): GO SUB Li n~ t o
7120 NEXT I
7130 RETl'FN

I
l
'"It
------ - II
l
Ji

Figure 11.4
Perspective Projections 189

Exercise 11.2
Draw various perspective views of a wire tetrahedron and a pyramid.

The Choice of Perspective Plane

The only value required for the perspective transformation that has not yet been
discussed is PPD, the distance of the perspective plane from the eye. We can see
from figure 11.1 that different values of PPD produce pictures of different sizes.
Which one do we choose? Is there a correct value?
If we consider the practical situation, we note that the observer is sitting in
front of a television and the perspective view plane is identified with the plane of
the television screen . Normally the observer is sitting at a distance that is about
three times the height of the screen from the terminal. In the scale of our map-
ping from the real-world to the graphics area of pixels, this is a distance 3*VERT
(the value we used above). If we choose PPD greater than this value it is as
though we are creating a close up, and if PPD is less than 3 *VERT we get the
smaller image of a long shot.

Clipping

Theoretically, objects may be positioned throughout space, even behind the eye,
although we consider only points with positive a-coordinates in the OBSERVED
position. Even so some of these points go outside the cone of vision and become
invisible. In fact, part of the cone of vision is outside the screen area (we can,
after all, see the outside of the graphics area) . We are left with a subset of the
cone of vision, the pyramid of vision . Thus all'points outside this pyramid (that
is, those whose perspective transforms take them off the screen) must be ignored .
We noted that the Spectrum displays an error message whenever we try to DRAW
a line to a point off the graphics area. It is essential that we use the clipped
'lineto' routine (listing 3.4) in order to avoid any problems . In fact we further
limit scenes so that all vertices in the OBSERVED position will have positive z-
values; that is, all objects must lie in front of the eye (although not necessarily
inside the cone of vision) . This will avoid peculiar perspective projections of
points that lie behind the eye appearing to be on the screen.

Exercise 11.3
Experiment with perspective views of all types of wire figures; for example,
bodies of revol.ution, regular solids . Consider cases where an object is drawn in-
side the construction routine ; that is, the values of V and W must now be calcu-
lated here and not in the 'drawit' routine. Change the program that drew the jet
of figure 9.3 so that you get a perspective view; note that the farther the eye gets
190 Advanced Graphics with the Sinclair ZX Spectrum

from the plane the smaller it appears, a phenomenon that does not occur with
the orthographic projection.

Exercise 11.4
Write a hidden line algorithm for a single convex body, similar to that given in
chapter 10.
Note that since a convex facet is projected into a convex polygonal area in the
view plane, all we need do is calculate the coordinates of the vertices of the
projected facet , and hence find whether the facet is in anti-clockwise (in which
case we draw it) or clockwise order (in which case it is ignored).

Exercise 11.5
Write a program that draws a perspective view of a mathematical surface , similar
to that given in chapter 10. The method will be exactly equivalent to listing 10.4 ,
with the exception that you must work with the V/W values rather than the
X/Yarrays.

These hidden surface and line algorithms are perfectly adequate for specially
defined single objects, but we must now consider the more general case where a
number of objects are scattered about space.

Complete Programs

I. 'lib 1" 'lib3' and listings 9.4 ('cube'), 11.1 ('scene3') and 11.2 ('drawit'). Data
required: HORlZ, VERT, and repeated values for (EX, EY, EZ) and
(DX, DY, DZ). Try 9,6, (5 ,15 ,10) and (0, 0, 0) ; (1 ,2,20) and (0, 0,1).
12 A General-purpose Hidden Line
Algorithm

As in previous chapters, we assume that objects are set up by the 'scene3'


routine, but now insist that the NOV vertices in the scene are stored in the X,
Y, and Z arrays. Their perspective projections on to the view plane are stored in
arrays V and W. The NOF facets are stored as a list of vertex indices (a maximum
of six) in array F, and the number of edges on any facet is placed in array H.
We assume that all objects are closed. Each object need not be convex but its
surface must be composed of convex facets that are stored in anti-clockwise
orientation. Thus it is impossible to see the underside of any facet; that is, when
projected on to the view plane we see only facets that maintain their anti-clock-
wise orientation. Strictly speaking, this means that we cannot draw planar objects .
If these are required for a particular scene then we avoid the problem by storing
each facet of a planar object twice - once clockwise and once anti-clockwise -
so whatever the position of the eye, on perspective projection we see one and
only one occurrence of the facet . We assume also that all lines in the scene are
the edges of two contiguous facets : if a single line is required it is stored as a
degenerate planar facet with two edges, These restrictions were imposed to speed
up the hidden line algorithm. This is very necessary because we are now approach-
ing the limits of the processing power of the Spectrum. Even simple pictures like
the two cubes in figure 12.1 take over 5 minutes to draw, the two stars of figure
12.2 take over 30 minutes. The Spectrum was never intended to run such com-
plex algorithms, and so it is great credit to the Sinclair design team that the
Spectrum does achieve such very good results.
Nevertheless, we think it is important to study general hidden line algorithms
for educational reasons. It is essential for anyone with more than a passing
interest in computer graphics to understand the problems implicit in drawing
views of three-dimensional objects with the hidden lines suppressed. The routine
given in listing 12.1 is such a hidden line algorithm, which can be transferred to
larger machines where it will run with ease. If you get the opportunity to use
more powerful computers it will be very instructive to run our programs on them .
In order to produce a hidden line picture of a scene stored in the OBSERVED
position, every line on the objects in the scene must be compared with every
facet. Because of the above restrictions we need compare the lines only with the
192 Advanced Graphics with the SinclairZX Spectrum

visible facets ; that is, those that , when projected, keep their anti-clockwise
orientation.
Let us assume that a typical line I'3 in the OBSERVED position joins the two
points (x I" Y I" Z I') and (X2:' Y2', Z2 '), and so a general point on this line is

Wesuppose that these two end points are projected on to the two points (x I' Y I)
and (X2' h) in the perspective view plane. Thus r 3 is projected on to this plane
as a line r 2 with general point

Note that the point (1 - 1/» (x I" Y I" Z 1 ') + I/>(X2', Y 2" Z 2') does not necessarily
transform into the point (1 - 1/» (Xl> yd + I/>(X2' Y2) : that is, I/> need not equal J.L.
Welet a typical facet il 3 be projected on to an area il 2 in the view plane and
assume that the H vertices on this projected facet are (Xt, Yt), where 1 .,;; i .,;; H
Let the i t h edge of il2 intersect r 2 at (1 - At) (Xt,Yt) + At(Xi+l.Yt+d. If
At < a or At > 1 then r 2 intersects the extended i th edge at a point outside the
area il2 : if a ~ At";; 1 then r 2 crosses the area il2 at a point on the i t h edge.
Since the projected projection of a convex facet is convex, then the number of
crossing points is either zero (and there is no point of intersection) or two
(perhaps coincident). We need consider only the case of two non-coincident
points: suppose their J.L values on I'2 are J.Lmin and J.Lmax where J.Lmin < J.Lmax . So
the points of intersection on r 2 are (1 - J.Lmin)(XI, yd + J.Lmin(X2, h) and
(1 - J.Lmax)(XI> yd + J.Lmax(X2' Y2) '
It is now necessary to discover whether the subsegment of I'2 between these
two points is visible or not. This is checked by finding the mid-point of the
segment (Xmid' Ymid) = (1 - J.Lmid) (XI, yd + J.Lmid(.X2; Y2), where J.Lmid =
CJ.Lmid + J.Lmax)/2. We then find the point (x, y, Z) on r 3 that has (Xmid, Ymid)
as its perspective projection. The segment of line between the points with J.L
values J.Lmin and J.Lmax is hidden if and only if (x, y, z) and the eye are on opposite
sides of the infinite plane containing ll3 . The equation of the plane is found
using the methods described in chapter 7, and the functional representation of
the plane is used to check the above requirement.
Note that x*PPD/z = Xmid, y*PPD/i =Ymid, and (x, y, z) lies on r 3 • So for
some value of I/>

Hence
A General-purpose Hidden Line Algorithm 193

and

that is

Ymid*ZI' - YI'*PPD
=
(Y2' - YI')*PPD - Ymid*(Z2' - Zl')

This enables us to calculate tfJ, and hence (x, y, z), which in tum is used to find
whether the subsegment r 2 is visible or not.
The algorithm given in routine 'hidden', listing 12.1, compares each line on
the objects with all the visible (anti-clockwise) facets. Note that all objects are
considered solid; that is, no individual planar facet occurs in such a way that it is
possible to see its underside (clockwise orientation). The lines are implicitly
stored in the facet data , and each line occurs twice, once from vertex IVI to
vertex IV2 (say) and once from vertex IV2 to IVI. Rather than duplicate effort
we consider only the case when IVI < IV2. Furthermore we compare the lines
with visible facets only, for if a line is partially obscured by a hidden facet (one
with clockwise orientation) then the invisible part of that line must also be
obscured by anti-clockwise facets.
Let us assume that at the time of comparing the line I'2 , which joins vertices
IVI to IV2 with the Kth facet, we have calculated NRL visible subsegments of
the line : NRL is assumed to be less than 50. The Il values for the end points of
the Mth visible segment are stored in array L at L(1,M) and L(2,M). Initially
NRL = 1, L(1, 1) = 0 and L(2, 1) = 1; that is, the complete line is assumed to be
visible. If at this stage a new hidden segment is discovered, specified by the values
Ilmin and Ilmax (the variables MIN and MAX), then the values in the L array and
NRL have to be adjusted accordingly.
When the line has been compared with all visible facets we are left with the
NRL visible segments that can then be drawn on the screen. If at any time NRL
becomes zero then the line is totally obscured and there is no need to continue
with comparisons with other facets.

Example 12.1
We can now draw a hidden line , perspective view of the scene we first saw in
figure 9.2: one of the two cubes shown in figure 12.1. The scene has HORIZ = 9,
VERT =6 and is viewed from (15,10,5) to (0, 0, 0).
194 Advanced Graphics with the Sinclair ZX Spectrum

Listing 12.1

7000 REM hidden/general hidde n line algorithm


7001 R[M I ~ : ~ CV , NO L , X ( NOV ) , Y ( NOV ) , Z ( NOV ) , V ( NOV ) , W (N0V ) ,
F(6,NOF),H(NOF),PPD,R(4,4)
7010 DIM L(2,50): DIM G(NOF): LET EPS = 0.000001
701P- REM check on 1 'th pro jected facet: a nt iclockwise set G(I)=1
7019 REM clockwise or dese pera te set G(I)=O.
7020 FOR I = 1 TO NOF
7030 LET 11 F(1,1): LET X1 = V(1): La Y1 w(1)
7040 LET 12 = F(2,I): LET X2 = V(I2): LET Y2 W(I2 )
7050 LET 13 = F(3,I): LET X3 = V(I3): LET Y3 W(3)
7060 LET DX1 = X2 - X1: LET DY1 Y2 - Y1
7070 LET DX2 = X3 - X2: LET DY2 = Y3 - Y2
7080 LET G(I) = 0
7090 IF DX1*DY2 - DX2*DY1 > 0 AND H( I ) > 2 THEN LET G(I)
7100 NEXT I
7109 REP find J'th l i ne on the edge of 1 'th facet.
7110 FOR I = 1 TO NOF
7120 LET HH = H(I): LET IV1 = F(HH,I)
7130 LET X1 = V(IV1): LET Y1 = W(IV1)
7140 FOR J = 1 TO HH
7150 LET IV2 = F(J,I)
7160 LET X2 = V(IV2): LET Y2 = W(IV2)
7170 IF IV1 > IV2 TH EN GO TO 8160
7179 REM initialise variabl es.
7180 LET NRL = 1: LET L(1,1) = 0: LET L(2,1) = 1
7190 LET CA = X2 - X1: LET CB = Y1 - Y2
7200 LET CC = -X1*CB - Y1*CA
7209 REM compare th is l ine with the K'th facet.
72H'J FOR K = 1 TO NOF
7220 IF G(K) = 0 THEN GO TO 8040
7230 IF K = I THEN GO TO 8040
7240 LET IN = H(K)
7249 REM l oop to f i nd two points of i nt e r se ct i on of pr ojected l i ne wit h
projected facet. These points specif ied by I'tJ va lues MIN and MAX.
7250 LET MAX = -1: LET MI N = 2
7260 LET JV1 = F(IN,K)
7270 LET VX1 = V(JV1 ): LET WY1 = W(JV1)
7280 LET S1 = SGN (CA*WY1 + CB*VX1 + CC)
7290 FOR M = 1 TO IN
7300 LET JV2 = F(M,K)
7310 LET VX2 = V(JV2): LET ~Y 2 = W(JV2)
7320 LET S2 =SGN (CA*WY2 + CB*V X2 + CC)
733f IF S1 = 52 THEN GO TO 7500
7340 LET XE = VX1 - VX2: LET YE = WY1 - WY2
7350 LET XF = VX1 - X1: LET YF = WY1 - Y1
7360 LET DISC = CA*YE + CB*XE
7369 RE~:if l ine is parallel to a line on the facet th en e xit f acet loop.
7370 IF ABS DISC> EPS THEN GO TO 7440
7380 IF ABS CA > EP5 THEN GO TO 7410
7390 IF AB S XF < EPS THEN GO TO 8040
7400 GO TO 7500
7410 LET LAMBDA = XF/CA
7420 IF ABS (XF + LAmDA*CB) < EPS THEN GO TO 8040
7430 GO TO 7500
7440 LET LAMBDA = (CA*YF + CB*XF)/DISC
7449 REM if l ine mi sses K'th facet then go to next fa cet.
7450 IF LAMBDA < -EPS THEN GO TO 7500
7460 IF LAMBDA> 1 + EPS THEN GO TO 7500
7470 LET MU = (YE*XF - XE*YF)/DISC
7479 REM a true intersection so update MAX and MIN.
A General-purpose Hidden Line Algorithm 195

7480 IF MAX < MU THEN LET MAX = MU


7490 IF MIN> MU THEN LET MIN = MU
750rl LET S1 = S2
7510 LET VX1 = VX2: LET WY1 = WY2
7520 NEXT M
7529 REM check i f intersections Lie between specified endpoints of Line.
7530 IF MIN> 1 THEN GO TO 8040
7540 IF MAX < rl THEN GO TO 8040
7550 IF MAX> 1 THEN LET MAX = 1
7560 IF MIN < rl THEN LET MIN = 0
7570 IF MAX - MIN < EPS THEN GO TO 8040
7579 REM caLcuLate XMID and YMID.
7580 LET MID = (MAX + MIN)*0.5: LET MUD = 1 - MID
7590 LET XMID = MUD*X1 + MID*X2
760rl LET YMID = MUD*Y1 + MID*Y2
7610 LET DENOM = PPD*(X(IV2) - X(IV1» - XMID*(Z(IV2) - Z( IV1»
7620 IF ABS DENOM < EPS THEN GO TO 7650
7629 REM caLcuLate PHI and hence XHAT, YHAT and ZHAT.
7630 LET PHI = (XMID*Z(IV1) - PPD*X (IV1»/DENOM
7640 GO TO 7670
7650 LET DENOM = PPD*(Y(IV2) - Y(IV1» - YMID*(Z(IV2) - Z(IV1»
7660 LET PHI = (YMID*Z(IV1) - PPD*Y(IV1»/DENOM
7670 LET ZHAT = (1 - PHI)*Z(IV1) + PHI*Z(IV2)
7680 LET FACT = ZHAT/PPD
7690 LET XHAT = XMID*FACT: LET YHAT = YMID*FACT
7699 REM caLcuLate coefficients of pLane containing facet : A,B,C and D.
770rl LET JV1 = F(1,K) : LET JV2 =F(2,K): LET JV3 = F(3,K)
7710 LET DX1 = XeJV1 ) - X(JV2)
7720 LET DX3 = X(JV3) - X(JV2)
7730 LET DY1 Y(JV1) - Y(JV2)
7740 LET DY3 = Y(JV3) - Y(JV2)
7750 LET DZ1 = Z(JV1) - Z(JV2)
7760 LET DZ3 = zeJV3) - zeJV2)
7770 LET A = DY1*DZ3 - DY3*DZ1
7780 LET B = DZ1*DX3 - DZ3*DX1
7790 LET C = DX1*DY3 - DX3*DY1
780rl LET D = A*X(JV1) + B*yeJV1) + C*Z(JV1)
7810 LET S1 = A*XHAT + B*YHAT + C*ZHAT - C
7819 REM i f facet hides part of Line then change the L array.
7820 IF ABS S1 < EPS THEN GO TO 8040
nm~ IF ABS (SGN S1 + SGN D) < 2 THEN GO TO 8040
7840 LET MORE = NRL
7850 FOR M= 1 TO NRL
7860 LET R1 = L(1,M): LET R2 = L(2,M)
7870 IF (R1 > MAX) OR (R2 < mr;> THEN GO TO 7960
7880 IF (R1 >= MIN) AND (R2 <= MAX) THEN GO TO 7950
7890 IF (R1 < MIN) AND eR2 > MAX) THEN GO TO 7920
790rl IF (R1 < MIN) THEN GO TO 7940
7910 LET L(1,M) = MAX: GO TO 7960
7920 LET MORE = MORE + 1
7930 LET L(1,MORE) = MAX: LET L(2,MORE) R2
7940 LET L(2,M) = MIN: GO TO 7960
7950 LET L(1,M) = -1
7960 NEXT M
7969 REM t idy up the L a rr ay.
7970 LET NRL = 0
7980 FOR M= 1 TO MORE
7990 IF L( 1,M) < - EPS TH EN GO TO 8020
80rl0 LET NFL = NRL + 1
8010 LET L( 1, NRL) = L(1,M): LET L(2,NRL) L(2,M)
8020 NEXT M
8030 IF NRL = 0 THEN GO TO 8160
196 Advanced Graphics with the Sinclair ZX Spectrum

8040 NEXT K
8049 Rl~ craw visibLe parts of Line ( if any).
8050 =
FOR K 1 TO NRL
8060 LET R1 = L(1,K): LET R2 = 1 - 1'1
8070 LET XP1 = X1*R2 + X2*R1
8080 LET YP1 = Y1~R2 + Y2*R1
8090 LET R1 = L(2,K): LET R2 = 1 - R1
810~ LET XP2 = X1*R2 + X2*R1
8110 LET YP2 = Y1*R2 + Y2*R1
8120 IF (ABS (XP1-XP2) < EPS) AND (ABS (YP1-YP2) < EPS) THEN GO TO 8150
8130 LET XPT = XP1: LET YPT = YP1: GO SUB moveto
8140 LET XPT = XP2: LET YPT = YP2: GO SUB Lineto
8150 NEXT K
8160 LET IV1 = IV2: LET X1 = X2: LET Y1 = Y2
8170 NEXT J
8180 NEXT 1
8190 RETURN

r-l
,' ------
........... /".--.-.....1-. _
e

L-N) l______________}~itI .'

Figure 12.1

We use 'lib 1" 'lib3' and 'hidden' (listing 12.1) together with the 'scene3' and
'cube' routines given in listing 12.2. This last version of 'cube' means that we
have considered all the array methods of constructing an object; that is, stored/
not stored, lines/facets . We deliberately used the cube over and over again in our
diagrams because it is such a simple object and it is easy to understand its various
constructions, and therefore it does not complicate our discussion of the general
principles of three-dimensional graphics. Now is the time to introduce complexity
into our objects: provided that you understand the limitations of the algorithms
then the ideas we have discussed will be equally valid. Users with the 16 K
Spectrum will find that programs of this complexity will not fit into their
machines. Such programs must be broken into independent sections and object
data and arrays must be stored temporarily on tape.
A General-purpose Hidden Line Algorithm 197

Listing 12.2
6000 REM scene3/figure 12.1
6010 DIM X(16): DIM Y(16): DIM Z(16)
6020 DIM V(16): DIM W(16): DIM F(4,12): DIM H(12)
6030 DIM A(4,4): DIM B(4,4): DIM R(4,4): DIM Q(4,4)
6040 LET cube = 6500: LET hidden = 7000
6050 LET FPD = 3*VERT: LET NOV = 0: LET NOF = 0
6059 REM put first cube in OBSERVED position: ( ACTUAL=SETUP).
6060 GO SUB idR3: GO SUB Look3
607E GO SUB cube
6079 REM copy ACTUAL to OBSERVED matrix i nt o Q.
6080 FOR I = 1 TO 4: FOR J = 1 TO 4
6090 LET Q(I,J) = R(I,J)
6100 NEXT J: NEXT I: GO SUB idR3
6109 REM caLcuLate SETUP to ACTUAL matrix.
6110 LET TX = 3: LET TY = 1.5: LET TZ = 2: GO SUB trar.3: GO SUB muLt3
6119 REM recover ACTUAL to OBSERVED matrix.
6120 FOR I = 1 TO 4: FOR J = 1 TO 4
6130 LET A(I,J) = Q(I,J)
6140 NEXT J: NEXT I
6149 REM caLcuLate SETUP to OBSERVED matrix.
6150 GO SUB muLt3
6159 REM pLace second cube and draw hidden Line view of scene.
6160 GO SUB cube
6170 GO SUB hidden
6180 RETURN

6500 REM cube/ vertices and facets (stored)


6501 REM IN PPD,NOV,NOF,X(NOV),Y(NOV),Z(NOV),V(NOV),W(NOV)
F(4,NOF),H(NOF),R(4,4)
6502 REM OUT: NOV,NOF,X(NOV),Y(NOV),Z(NOV),V(NOV),W(NOV)
F(4,NOF),H(NOn
6510 DATA 1,1,1, 1,1,-1, 1,-1,-1, 1,-1,1, -1,1,1, -1,1,-1, -1,-1,-1, -1,-1,1
6520 DATA 1,2,3,4, 5,8,7,6, 1,5,6,2, 2,6,7,3, 3,7,8,4, 4,8,5,1
6530 RESTORE cube
6539 REM extend data base of vertices in OBSERVED position.
6540 LET NV = NOV
6550 FOR I = 1 TO 8
6560 READ XX,YY,ZZ: LET NOV NOV + 1
6570 LET X(NOV) = XX*R(1,1) + YY*R(1,2) + ZZ*R(1,3) + R(1,4)
6580 LET Y(NOV) = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4)
6590 LET Z(NOV) = XX*R(3,1) + YY*R(3,2) + ZZ*R(3,3) + R(3,4)
6599 REM perspective transform.
6600 LET V(NOV) PPD*X(NOV)/Z(NOV)
6610 LET W(NOV) = PPD*Y(NOV)/Z(NOV)
6620 NEXT I
6629 REM read and extend data base of facets.
6630 FOR I = 1 TO 6
6640 READ F1,FZ,F3,F4: LET NOF = NOF + 1
6650 LET H(NOF) = 4
6660 LET F(1,NOn F1 + NV: LET F(Z,NOn F2 + NV
6670 LET F(3,NOF) = F3 + NV: LET F(4,NOF) F4 + NV
6680 NEXT I
6690 RETURN
198 Advanced Graphics with the Sinclair ZX Spectrum

Listing 12.3

650~ REM i cosa/ hedr on


6501 REM IN and OUT : same as cube above.
65111J DATA 0,1,T, T,0,1, 1,T,0, 0,-1,T, T,0,-1, -1,T,0, 0,1,-T
-T,0,1, 1,-T,0, 0,-1,-T, -T,0,-1, -1,-T,0
65211J DATA 1,3,2, 1,2,4, 1,4,8, 1,8,6, 1,6,3, 2,3,5, 2,9,4, 4,12,8
8,11,6,3,6,7, 2,5,9, 4,9,12, 8,12,11, 6,11,7, 3,7,5, 5,111J,9
9,11',12, 12,11',11, 11,1~,7, 7,11',5
6531' RESTORE icosa: LET T = (1 + SQR 5)/2
6540 LET NV = NOV
65511J FOR I = 1 TO 12
6560 READ XX,YY,ZZ: LET NOV NOV + 1
6571' LET X{NOV ) XX*R{1,1) + YY*R{1,2) + ZZ*R{1,3) + R{1,4)
65811J LET Y{NOV) XX*R{2,1l + YY*R{2, 2) + ZZ*R{2,3) + R{2,4)
6590 LET Z{NOV) XX*R{3,1) + YY*R{3,2) + ZZ*R{3,3) + R{3,4)
6611J~ LET V{NOV) X{NOV)*PPD/Z{NOV)
6611' LET W(NOV) Y{NOV)*PPD/Z(NOV)
66211J NEXT I
663~ FOR I = 1 TO 21'
6640 READ F1,F2,F3: LET NOF = NOF + 1
6650 LET H{NOn = 3
66611J LET F(1,NOF) = F1 + NV: LET F{2,NOF) F2 + NV: LET F{3,NOF) F3 + NV
66711J NEXT I
66811J RETURN

Listing 12.4

6711J~ REM cuboct/ahedron


67~1 REM IN and OUT : same as cube above.
67111J DATA 0,1,1, 1,0,1, 1,1,0, 0,-1,1, 1,0,-1, -1,1,0, 0,1,-1
-1,0,1, 1,-1,0, 0,-1,-1, -1,0,-1, -1,-1,0
67211J DATA 1,2,4,8, 1,6,7,3, 2,3,5,9, 4,9,1~,12, 5,7,11,1~, 6,8,12,11
6731' DATA 1,3,2, 1,8,6, 2,9,4,3,7,5, 4,12,8, 5,1~,9, 6,11,7, 10,11,12
6740 RESTORE cuboct
6750 LET NV = NOV
6760 FOR I = 1 TO 12
67711J READ XX,YY,ZZ: LET NCV NOV + 1
6780 LET X{NOV) XX*R{1,1) + YY*R{1,2) + ZZ*R{1,3) + R(1,4)
6790 LET Y{NOV) XX*R(2,1) + YY*R{2,2) + ZZ*R(2,3) + R{2,4)
6800 LET Z{NOV) XX*R{3,1) + YY*R{3,2) + ZZ*R{3,3) + R{3,4)
6811' LET V{NOV) X(NOV)*PP D/Z(NOV)
6820 LET W(NOV) Y(NOV)*PPD/Z(NOV)
6831' NEXT I
6840 FOR I = 1 TO 6
6850 READ F1,F2,F3,F4: LET NOF = NOF + 1
6861' LET H{NOF) = 4
6870 LET F<1,NOF) = F1 + NV: LET F{2,NOF) F2 + NV: LET F<3,NOF) F3 + NV
: LET F{4,NOF) = F4 + NV
6880 NEXT I
6890 FOR I = 1 TO 8
690~ READ F1,F2,F3: LET NOF = NOF + 1
6911' LET H(NOn = 3
6921' LET F(1,NOn = F1 + NV: LET F{2,NOF) F2 + NV: LET F<3,NOn F3 + NV
6931' NEXT I
6940 RETURN
A General-purpose Hidden Line Algorithm 199

Exercise 12.1
Construct hidden line scenes composed of cubes, tetrahed ra, pyramids, octa-
hedra , cubo ctahedra, icosahedra . To help you , listings 12.3 and 12.4 give con-
struction routines for a cub octahedron and icosahedron. Write your own routines
for an octahedron, and perhaps even more complicated objects like the rhombic
dodecahedron (see Coxete r, 1974).

Listing 12.5
6 000 REM scene3/ t wo s ta rs hidde n line s removed
60 10 DI M X(22): DI M Y( ZZ): DIM Z(Z2 )
602 0 DI M V( 2Z) : DI M W( Z2 ): DIM F(3,3 6 ' : DIM H( 36 )
6 03 0 DI M A( 4,4) : DI M B( 4, 4 ): DIr. R(4 ,4) : DIM Q( 4,4 )
6 0 4111 LET s tar1 = =
65 111 0: LET s t a r ? 67 1110 : LET hidden =
7 0 00
6050 LET PPD =3*VERT: LET NOV = 111: LET NOF = 0
6059 RE M p Lac e f i rst st ar .
60 60 GO SUB i d R3 : EC' SUfi Look3
6070 LET A = 6: GO SUB s t a r 1
6080 FO R I = 1 TO 4 : FOR J = 1 TO 4
60 9111 LET Q(I, J) = R(I,J )
6 100 NEXT J: NEXT I: GO SUB i d R3
6 109 REM p La ce sec ond st a r.
6 110 LET TX = 5 : LET TV = 5 : LET TZ 5 : GO SUB tran3 : GO SUB mult3
61 20 FOR I ~ 1 TO 4 : FOR J = 1 TO 4
613 0 LET A(I,J ) = Q(I , J)
614111 NEXT J : NEXT I
61 50 GO SUB muL t3
6 160 LET A = 4: G0 SUB s ta r2
6170 GO SUB hi d de n
6180 RETUF.N

Listing 12.6
6500 RE~1 s t a r 1
65 0 1 REM I N and OUT : same as cu be a bov e.
65111 9 REM s t ar based on a c ub e .
65 H l DA TA 1,1,1,1,1,-1,1,- 1,-1,1,-1,1, - 1,1,1, - 1 ,1,-1, - 1,-1,-1, - 1,-1 , 1,
A, 0,11I, -A,0 ,0 , I1I , A, 0 , 0 , -A ,0 , 0,I1I, A, 0,11I,-A
6 52 0 DATA 1 ,2 ,9 , 2 ,3 ,9 , 3 ,4 ,9 , 4 , 1 ,9, 6 ,5 ,10 , 5, 8 ,1 0, 8 ,7 ,1111 , 7,6 ,1 0 ,
2 ,1 , 1 1 , 1 , 5 ,1 1 , 5,6,11, 6 ,2 , 11 , 4,3 , 1 2, 3,7,1 2, 7 , 8 ,12 , 8 , 4 ,12 ,
1,4,1 3,4, 8,13, 8 , 5 , 13 , 5 ,1 , 13 , 3, 2,1 4, Z,6 , 14 , 6 ,7 ,14 ,7 , 3 ,1 4
6 530 RESTORE s t a r 1
6 540 LET NV = "JQV
6550 FOR I = 1 TO 1 4
6 560 R E ~. D XX, YY, ZZ: LET NOV NOV + 1
65 70 LET X(NOV) XX* R(1 , 1) + YY *R( 1 , Z) + ZZ*R( 1 ,3) + R( 1 ,4)
6 580 LET Y(NOV) XX*R(Z,1) + YY *R(Z , 2) + ZZ*R(2 ,3) + R(2 ,4)
65 90 LET Z( NOV) XX* R( 3 , 1 ) + YY*R (3 , 2) + ZZ*R(3 ,3) + R( 3 , 4 )
6 6 0 0 LET V( NOV) PPD*X( NOV )/Z(NOV )
6610 LET W(NOV) =PPD*Y( NOV) / Z(NOV)
66 2111 NEXT I
6630 FOR I =1 TO 24
6640 REM F1, F2,F 3: LET NOF = NOF + 1
6650 LET H(NOF) =3
6660 LET F(1,NOF) F1 + NV : LET F<Z,NOF ) F2 + NV: LET F<3,NOF) F3 + NV
667 0 NEXT I
66 80 RETURN
200 Advanced Graphics with the Sinclair ZX Spectrum

Listing 12. 7
671i'H'1 REM sta r2
6701 REM IN ~n d OUT : same as cube above.
6709 REM star based on a tetrahed ron.
6710 DATA 1,1,1, 1,-1,-1, -1,1,-1, -1,-1,1, -A,-A,-A, -A,A,A, A,-A,A, A,A,-A
6720 DATA 2,1,8, 3,2,8, 1,3,8, 1,Z,7, 4,1,7, 2,4,7,
2,3,5, 4,2,5, 3,4,5, 3,1,6, 4,3,6, 1,4,6
6730 RESTORE st a r2
6741lJ LET NV = NOV
6750 FOR 1 = 1 TO 8
6760 READ XX,YY,ZZ: LET NOV = NOV + 1
6770 LET X(NOV) = XX*R(1,1) + YY *R(1, 2) + ZZ*R(1,3) + R(1,4)
6780 LET Y(NOV ) = XX*R(2,1) + YY*R(2,2) + ZZ*R(2,3) + R(2,4 )
6790 LET Z(NOV) = XX*R(3, 1) + YY*R(3,2) + ZZ*R(3,3) + R(3,4)
6800 LET V(NOV) = PPD*X(NOV )/Z(NOV)
6810 LET W(NOV) = PPD*Y(NOV)/Z(NOV)
6820 NE XT 1
6830 FOR 1 = 1 TO 12
6840 RE AD F1,F2,F3: LET NOF = NOF +
6850 LET H010 F) e: 3
6860 LET F(1,NOF) = F1 + NV: LET F(Z,NOF) F2 + NV: LET F<3,NOF) F3 + NV
6870 NEXT 1
688ft RETL'RN

Example 12.2
By now you will have realised that hidden line algorithms are very slow programs
- we have to make a large number of comparisons. It takes at least 5 minutes to
draw the two cubes of figure 12.1 . This means that we are rather limited in the
scope of objects we can draw. Nevertheless it is very good practice, and if you
have the opportunity to use larger machines you will see that the above algor-
ithm will work on these also, but much faster. We give a 'scene3' routine in
listing 12.5 and examples of two three-dimensional star-shaped objects in list-
ings 12.6 and 12.7 (both require a parameter A that changes the elongation of
the spikes). These two 'star' routines are based on the tetrahedron and cube.
Figure 12.2 was drawn with HORIZ = 48, VERT = 32, viewed from (35, 20 , 25)
towards (0 , 0, 0).

Figure 12.2
A General-purpose Hidden Line Algorithm 201

Exercise 12.2
The program in listing 10.1 checks that the order of the vertices of a triangular
facet are anti-clockwise . The program was devised for use with convex bodies
containing the origin . Extend it so that it can cope with the most general case;
that is, specify the position of the observer and the coordinates of a point inside
the object (not necessarily the origin) so that this point and the observer lie on
opposite sides of the infinite plane containing the facet. Use this program to
check the above star-shaped objects (in fact for these figures the origin could act
as the inside point) .
Then produce your own star-shaped objects based on an octahedron, cubocta-
hedron, icosahedron or dodecahedron . Always check the order of the vertices in
your facets. You can produce stars based on very simple bodies of revolution,
and we need not limit ourselves to symmetrical objects! For non-symmetrical
shapes you really need the extended version of program 10.1 . Provided that you
stay within the restrictions mentioned, then listing 12.1 will draw any shape.

Exercise 12.3
Add extra information about the objects you are setting up. As well as the ver-
tex and facet information, introduce another array L such that L(l ,I) and
L(2,I) hold the indices of the two facets that have the Ith line as their intersec-
tion, I ~ I ~ NOL. Then change the hidden line algorithm so that it ignores any
line that borders two invisible (clockwise) facets, and does not compare a facet
with lines that lie in that facet.

Now you have read (and understood) chapters 7 to 12 you will have found
that we have reached the limits of three -dimensional graphics on the Spectrum.
You must have access to larger computers if you wish to go further in your study
of this type of computer graphics . Moreover, you must study the techniques of
using data structures, as opposed to arrays, for setting up scenes. For example , a
complete scene can be regarded as a linked list of pointers, each of which refers
to a linked list of information about the facets on a particular type of object. The
facets themselves can be stored as lists of vertices! A seemingly complex idea, but
one that makes the context checking of such programs as hidden line algor-
ithms very much simpler. The relationships between objects and facets are
implicitly stored in the lists. When you have grasped these ideas you can go on
to the complicated graphics algorithms including methods for animating , colour-
ing and shading. We recommend books by Horowitz and Sahni (1976), and
Knuth (1972,1973,1981) for the study data structures, and by Newman and
Sproull (1973) for the really complex graphics methods. In the next chapter we
take a look at more advanced character graphics and introduce one method of
producing animated three-dimensional drawings.
202 Advanced Graphics with the Sinclair ZX Spectrum

Complete Programs

I. 'lib I " 'lib3', listings 12.1 ('hidden') and 12.2 ('scene3' and 'cube'). Data
required : HORIZ, VERT, (EX, EY, EZ), (DX, DY, DZ). Try (a) 9, 6,
(15,10,5), (0, 0, 0); (b) 9, 6, (-10,10, -10), (0,1,0).
II. 'lib1" 'lib3', listings 12.1 ('hidden') and 12.2 ('scene3'). MERGE listing 12.3
('icosa') and 12.4 ('cuboct') and change the 'scene3' routine as follows

6010 DIM X(24): DIM Y(24) : DIM Z(24)


6020 DIM V(24): DIM W(24): DIM F(4, 34): DIM H(34)

6040 LET cuboct=6700: LET icosa=6500: LET hidden=7000

6070 GO SUB icosa

6160 GO SUB cuboct

Data required: HORIZ, VERT, (EX, EY, EZ), (DX, DY, DZ). Try (a) 9, 6,
(15,10,5), (0, 0, 0); (b) 9, 6, (-10,10,10), (0 ,1,0).
III. 'lib1', 'lib3' ,listings 12.1 ('hidden'), 12.5 ('scene3'), 12.6 ('starl') and 12.7
('star2'). Data required: HORIZ, VERT, (EX , EY, EZ), (DX, DY, DZ). Try
(a) 60,40, (10, 20, 30), (0, 0, 0); (b) 90 ,60 , (-10, 20, -10), (0, 1,0).
13 Advanced Programming Techniques

To give your programs that really professional quality it is essential to make


them user friendly. This is one of the few pieces of advertising jargon that
actually bears any relation to reality : it is essential to make programs easy to
use, not just for yourself but for other people. Wehave all returned to programs
written in a hurry three months previously, only to find that they are so badly
structured/commented that we cannot understand them. It is good programming
practice to comment on your programs as well as making their output self-
explanatory . Ensure that the prompts displayed while you are actually RUNning
the program are clear and concise . Another simple way of providing help is to
include an introductory instruction routine as found on most video games.
In programs where a set of routines can be used in any sequence or combina-
tion, the usual method of providing for selection between options is the menu
(see the CHARACTER GENERATOR program in chapter 5). Provided that the
prompts are appropriate to the actions they initiate, this method is especially
useful for people who do not understand the details of the program and are
using it only as a drawing tool. Common sense plays its part in deciding what
prompts should be issued. Avoid such classic misprompts as PRESS 1 FOR
DUPLICATE DATA OR 2 FOR SINGLE DATA. If possible use cursor keys for
movements about the screen (see option 3 of the CHARACTER GENERATOR
program in chapter 5) : this will seem natural to any regular user of the Spectrum .
Listing 13.1 shows a program that might be used to draw polygons (as in exer-
cise 1.3). The 'input' routine uses the 'EDIT' and cursor keys and is designed for
people familiar with programming on the Spectrum.

Control Codes

The INPUT command can be used to issue a prompt immediately prior to any
request for a data item. In most cases we just place the prompt, enclosed in
quotes , in the exact form we wish to be displayed, before the item in the INPUT
statement. On the Spectrum we can force the evaluation of any string expression,
including function calls, by placing brackets around the expression. In this way it
will be treated as though it were a prompt in quotes . This method is used simply
in the above listing but we can produce far more complex prompts. By building
204 Advanced Graphics with the SinclairZX Spectrum

Listing 13.1

10 DIM X(10): DIM Y(10)


20 LET input = 200: LET List = 300
30 GO SUB input
40 PLOT X(10),YC10): LET OX =
X(10): LET OY = Y(10)
50 FOR I = 1 TO 10: DRAW XCI) - OX,YCI) - OY
: LET OX =
XCI): LET OY =
YCI): NEXT I
60 PAUSE 250: GO TO 30

200 REM input coords


210 LET I = 1
220 GO SUB List
230 LET IS = INKEYS: IF IS = "" THEN GO TO 230
240 IF IS = CHRS 10 AND I < 11 THEN LET I = I + 1: GO TO 220
250 IF IS = CHRS 11 AND I > 1 THEN LET I = I - 1: GO TO 220
260 IF IS <> CHRS 7 THEN GO TO 230
270 IF I = 11 THEN INPUT "End. ? "; LINE 1$: IF IS = "y" THEN CLS RETURN
280 IF I = 11 TH EN GO TO 220
290 INPUT "X Coord. ";XCI),"Y Coord. ";Y(I): GO TO 220

300 REM List data


310 CLS : FOR J = 1 TO 10
320 PRINT AT J,1; "X Coord. ";X CJ) , "Y Coord. ";YCJ)
330 NEXT J: PRINT AT 11,1;"End.": PRINT AT 1,0;">"
340 RETURN

up a string containing control codes we can display complicated coloured


graphics anywhere on the screen. A named variable string can even be built up
in several stages and the variable name placed in the INPUT command inside
brackets. Control CODEs may be included in the strings using the CHR$ func-
tion, and numeric variables can be included by using STR$. This technique is
shown to good effect in the MASTER MIND program (listing 5.6) and also in
the WORM GAME (listing 1.16). Strings with built-in colour CODEs or even
PRINT AT CODEs can be used in games or other programs to provide rapidly
changing displays on all parts of the screen. For example, a sample menu of a
mythical me-handling system is given in listing 13.2. Note the obvious use of
colours to warn .of potentially dangerous options.
Control codes may be entered from the keyboard (see page 115 of the
Spectrum BASIC Handbook (Vickers, 1982)) for direct inclusion in strings.
These direct CODEs, which are ignored in execution, can be included also in
program statements to emphasise or hide parts of listings . On our accompanying
tape we give program listings in which the REM statements at the start of each
routine begin with the CODEs for BRIGHT 1 (extended "9") and end with
BRIGHT 0 (extended "8"). To pad out REM statements so that they end
exactly at the edge of the screen we need to insert a CODE 6 in the line, which
is equivalent to a comma in PRINT statements. Although not obviously avail-
able from the keyboard, we can achieve the desired effect by inserting the
CODEs for PAPER 6 (extended "6") and then immediately press DELETE.
This removes the CODE for PAPER but leaves the CODE 6, which has the
effect of making the cursor leap ahead to the next half or full line position.
Advanced Programming Techniques 205

Listing 13.2

100 DIM G(6): DIM A$(6,24)


110 FOR I =
1 TO 6: READ G(I): NEXT I
120 DATA 1000,1000,1000,1000,1000,1000
130 LET A$(1) ="
EDIT FILE": LET A$(2) ="
PRINT FILE"
140 LET A$(3) ="
SAVE FILE" : LET A$(4) ="
LOAD FILE"
150 LET A$(5) =
CHR$ 17 + CHR$ 2 + CHR$ 16 + CHR$ 7 + " DELETE FILE"
+ CHR$ 17 + CHR$ 7
160 LET A$(6) =
CHR$ 17 + CHR$ 2 + CHR$ 16 + CHR$ 7 + " ERASE ALL FILES "
+ CHR$ 17 + CHR$ 7

500 REM menul seLect options


510 CLS : PRINT AT 2,8;"N.0.N. FILE HANDLER"
520 FOR I = 1 TO 6
530 PRINT AT I*2 + 4,8;I;" ";A$(I)
54rl1 NEXT I
550 INPUT "SELECT OPTION 1";OP
560 IF OP < 1 OR OP > 6 THEN GO TO 55rl1
570 IF OP < 5 THEN GO TO 600
58rl1 INPUT ( "DO YOU REALLY WANT TO ";+CHR$ 6 + A$(OP) + " ");Y$
590 IF Y$ <> "y" THEN GO TO 550
600 GO SUB G(OP): GO TO 500

1000 REM remainder of routines


1010 RETURN

Here CODE 6 is interpreted in its own right and not as a parameter following the
CODE for PAPER. A CODE 6 at the end of each line preceding a new section of
program can be used to force the display of a blank line in the listing. The word
REM can be hidden by placing CODEs for INK 0 (extended shift "0") after
REM and INK 7 (extended shift "7") before it.
As a rule it is best to write programs in modules . Highlighting the names of
the modules allows us to read , correct and adapt the programs with ease. To
demonstrate the improved legibility provided by these highlighting techniques
see figure 13.1, which shows part of listing 13.4 as it appears on the screen.

Structure of the Display File

We know that the display me can be directly altered or examined by BASIC


programs, but to make use of this facility we must understand how the display
me is organised. Each horizontal line on the display is made up of 32 bytes,
each of eight bits . These 32 bytes are stored in consecutive locations in the
memory. However the bytes for the next line down are held in the equivalent
position on the next page of memory . For an eight-bit processor, like the Z80
contained in the ZX Spectrum, one page of memory is 28 or 256 bytes: we shall
use the identifier PAGE to refer to this quantity. This arrangement is designed
to help the video circuitry cope efficiently with the display. Thus each page has
room for eight lines of 32 bytes. The first page of the display me contains the
top line for each of the first eight rows of character blocks. To complete the
206 Advanced Graphics with the Sinclair ZX Spectrum

l o a d er fO I
maChine-COde ro utl n~
CLEAR 639.99
FOR -r=a TO :'L1 : .R E A D R
POKE? ~00TI ~ R : NEXT I
for
fe r r o u t u r-e

-
mClln o , oc ,a m
FOR - I =0 TO 2 -1-
:::::a-. TO 3 1. : PR INT AT I ~J

Figure 13.1

remaining sevenlines for these rows there are seven more pages of memory,
each page containing the data for subsequent lines. After these eight pages there
are another two sets of eight pages holding the line information for the rest of
the screen. From this we can calculate which bytes holds the data for the top
line of a character block, and know that each of the other lines down the block
is stored 256 bytes (one page) farther on. To work out the display-me position
of the top line of a character block we need to know in which third of the screen
(eight pages) the block lies. We need also to identify which of the 256 blocks in
this third we are considering. Wecalculate the position of the first line of a
character block in row R, column C by the following FuNction

DEF FN A(R,C) = 16384 + INT (R/8)*2048 +(R - INT(R/8)*8)*32 + C

This function is made up of four parts

16384 (to the start of the display me)


+ INT (R/8)*2048 (add relevant third of screen (0, 1,2) multiplied by the
length of one-third of the screen (2048 = 8*PAGE»
+ (R - INT(R/8)*8)*32 (plus the position of the row within that third of
the screen (0-7) multiplied by 32 (columns per row»
+ C (plus the column (0-31) within that row)
Advanced Programming Techniques 207

The Z80 also has internal registers, in which numbers can be placed, and used in
the first lines of that particular third of the screen. The last two items establish
which of the 256 bytes along the page corresponds to the top line of the
character block.
Using another function with a character as the input parameter, we can find
the start of the data that define this character and then transfer these data to the
display-file locations

DEF FN T(A$)= PEEK 23606 + PEEK 23607*256 + 8*CODE A$

The above function uses the system variable CHARS (stored in locations
23606 and 23607, see chapter 5) to find the start of the table of character set
data. It then adds eight times the CODE for the required character and thus
finds the address of the first piece of data . Note that these two functions can be
used to write on the bottom two lines of the display, which are not normally
accessible, as is demonstrated by the program in listing 13.3.

Listing 13.3
100 REM main program
110 LET pri nt =
500
120 LET P$ = "9 FAKE statement, 120:1": LET ROW = 23: LET COL = 0
130 GO SUB pri nt
14l.!1 LET P$ = "print this anywhere on the screen": LET ROW = 7: LET COL = 16
150 GO SUB pri nt
160 PAUSE 250: STOP

500 REM pri nt rout i ne


510 DEF FN A(R,C) =
16384 + INT (R/8)*2048 + (R - INT (R/8)*8)*32 + C
520 DEF FN D(A$) =
PEEK 23606 + 256 * PEEK 23607 + 8*CODE A$
530 FOR I =
1 TO LEN P$
540 LET ADDRESS =
FN A(ROW,COL)
550 LET DATA1 =
FN D(P$(I»
560 FOR J = 0 TO 7
570 POKE ADDRESS + J*256, PEEK (DATA1 + J)
580 NEXT J
590 LET COL =
COL + 1: IF COL =
32 THEN LET COL 0 =
: L ET ROW =
ROW + 1 : IF ROW =
24 THEN LET ROW = 0
600 NEXT I
610 RETURN

Rapid Transfer of ScreenData

If we try to move the display me of the Spectrum about rapidly, we soon flnd
that BASIC is not fast enough to transfer the required quantity of data adequate-
ly . The Spectrum is controlled by a Z80 microprocessor that is ideally suited to
the task of moving data about quickly. To program this directly (instead of
using BASIC as an intermediate language) involves an excursion into machine-
code. The Z80 machine-code has instructions, like the PEEK and POKE of
BASIC, which can be used to examine or replace numbers in various locations .
208 Advanced Graphics with the Sinclair ZX Spectrum

The Z80 also has internal registers, in which numbers can be placed , and used in
much the same way as variables in BASIC. So we can write a set of machine-code
instructions (that is, a program) to load one of these registers with a number from
a memory location, and then load the number from the register into another
memory location. This may not sound very interesting until you realise that the
Z80 chip can carry out this program about a million times in one second!
Unfortunately machine-code appears rather incomprehensible to a beginner,
looking like a stream of apparently unrelated numbers. It is more convenient to
use assembly language , which contains short words, mnemonic codes, that are a
great help in understanding the function of each machine-code instruction. The
Spectrum requires machine-code instructions to be stored in DATA statements
and then POKEd into the memory. It is helpful to include the assembly language
instructions as a REMark in the DATA line . Assemblers are programs that trans-
late assembly language into machine-code, but if an assembler is unavailable we
can use the table given in appendix A, page 183, of the Spectrum BASIC Hand-
book (Vickers, 1982) . One of the most powerful instructions available on the
Z80 chip is 237, 176 or, more comprehensibly, LDIR in assembly language . This
stands for LoaD and Increment Repeated, and is an instruction used to transfer
blocks of data from one place to another in the store. Before issuing this instruc-
tion , however, we must load some of the registers with various information. We
must load

DE with the address of the destination for the data


HL with the current address of the data
BC with the number of bytes to be transferred

For clarity we look at figure 13.2, an example machine-code routine, with the
equivalent Assembly language, and also a BASIC program, which performs
exactly the same function. Remember the Assembly language is just a way of
making machine-code more understandable. The complete program, listing 13.4,
POKEs the machine-code into the memory and then calls the routine. This
example copies the bottom third of the display me into the top third of the
screen.

300 REM BASIC data transfer


17,0,64 LD DE,16384 310 LET DE = 16384
33,0,80 LD HL,20480 320 LET HL = 20480
1,0,8 LD BC,2048 330 LET BC = 2048
237,176 LDIR 340 LET A =PEEK HL: POKE DE,A
350 LET DE =DE + 1: LET HL =HL + 1
360 LET BC = BC -, 1
o
370 IF BC 0 THEN GO TO 340
201 RET 380 RETURN

Figure 13.2
Advanced Programming Techniques 209

Having POKEd the machine-code instructions into the memory we run the
routine by using the USR function with the start address of our routine. USR
with a numerical address simply calls the subroutine , in machine-code , starting
at that address. This call is executed in a BASIC program by a command like
LET A = USR 32000 (32000 is the address holding 17, the first byte of code).

Listing 13.4
10 REM Loader for machire-code rout ire
19 REM for 16K machires use cLear 31999.
20 CLEAR 63999
30 FOR 1=0 TO 11: READ A
39 REM for 16K use POKE 320~~.
40 POKE 64l1J~~ + I,A: NEXT I

10~ REM data for machire-code transfer routine


110 DATA 17 ,0,64 REM LD DE,16384
120 DATA 33,0,80 REM LD HL,20480
130 DATA 1,0,8 REr" LD BC,2048
140 DATA 237,176 REM LDIR
150 DATA 201 REM RET

211l~ REM main program


210 CLS : FOR I = III TO 21
220 FOR J =
III TO 31: PRINT AT I,J;CHR$ (I + 64): NEXT J
230 NEXT I
240 PRINT AT 19,1; INVERSE 1 ;"PRESS ANY KEY TO START ROUTINE"
250 IF INKEY$ =''''THEN GO TO 250
259 REM for 16K change to USR 320~~.
260 LET A =
USR 640~~: STOP

Exercise 13.1
Type in the BASIC routine from figure 13.2 and time how long it takes to run .
Compare this with the time taken for the machine-code routine in listing 13.4.
You will find the machine-code is thousands of times faster.

Animation (48K machines only)

We use a simple routine to transfer all the data necessary to display a picture
(both display me and attribute me) from somewhere else in the memory to the
screen memory locations. This provides a quick method of changing between
pictures. There is enough memory on the 48K Spectrum to hold five alternative
pictures or frames. We can use the program from listing 13.5 to construct five
machine-code routines at 30100,30200,30300,30400 and 30500 that will
transfer these pictures to the screen. Suppose five diagrams have been SAVEd on
tape. We LOAD them into the alternative frames in memory , from where they
can be copied on to the screen by calling the appropriate routine. This method
could be used to illustrate a lecture or a sales talk with a short slide show, switch-
ing almost instantaneously between slides. Naturally after five slides have been
shown then five more must be LOADed. This takes approximately 5 minutes
from tape but less than 10 seconds from disk.
210 Advanced Graphics with the Sinclair ZX Spectrum

Pressingone of the keys "1 " to "5 " when using the routine 'slideshow'
(listing 13.5) brings the required picture to the screen.

Listing 13.5
10~ REM loader for machine-code routines
110 CLEAR 29999: DIM F(5)
120 FOR I = 1 TO 5: RESTORE
130 LET F(I) =
120 + 27*(1 - 1)
14l;l FOR J = 0 TO 11
150 READ A: POKE 30~~~ + I*1~~ + J,A
160 NEXT J
170 NEXT I

20~ REM data transfer from 1 ' t h frame to screen


210 DATA 17,0,64 REM l.D DE,16384
220 DATA 33,0,F(I) REM LD HL, FRAME (I)
230 DATA 1,0,27 REM LD BC,27*256
240 DATA 237,176 REM LDIR
250 DATA 201 REM RET

30~ REM load frames


31 ~ FOR J =
1 TO 10 : BEEP 0.1,3~: PAUSE 5: NEXT J
320 CLS : FOR I =
0 TO 4
330 LOAD "" CODE (120 + 1*27>*256,27*256
34l;l NEXT I
350 FOR J = 1 TO 10: BEEP 0.1,3~: PAUSE 5: NEXT J

40~ REM s Li de show


410 IF INKEY$ <> " " THEN GO TO 4Hl
420 LET A$ = INKEY$: IF A$ ="" THEN GO TO 420
430 IF A$ = CHR$ 13 THEN GO TO 310
440 IF A$ = "m" THEN GO TO 50~
450 IF A$ >= "1" AND A$ <= "5" THEN LET A = USR (30~00 + VAL A$*1rJ0)
460 GO TO 410

500 REM movi e show


510 FOR I =301~~ TO 3050~ STEP 100
520 LET A =USR I
530 IF INKEY$ = "s" THEN GO TO 4l;l0
540 NEXT I: GO TO 510

This idea can be extended to produce 'movie's. For example, consider figure
13.3, which shows five frames produced by the three -dimensional routines of
chapter 11. These give views of the same spheroid are created using HORIZ =
3.2, VERT =2.2, NUMH = 10, NUMV =8 and PHI =0.4 *PI * IjNUMH, where
o~ I ~ 4. The 'movie' of this object , viewed from (1 ,2 ,3) to (0 , 0, 0) , can be
shown apparently rotating by repeatedly bringing the five frames on to the screen
in quick succession. This set of pictures is included on the tape and is shown
below.
After you have finished with the 'movie' or 'slideshow' program you should
type CLEAR 65367, for otherwise the next time you LOAD a program the
Spectrum will reply 'Out of Memory'.
Advanced Programming Techniques 211

(a) (b)

(c)

(d) (e)

Figure 13.3
212 Advanced Graphics with the Sinclair ZX Spectrum

Exercise 13.2
Draw a perspective view of a wire cube in frame 1, and the same view, but with
the hidden lines suppressed, in frame 2. Produce a movie consisting of these two
frames only. You will see the visible lines of the cube stay fixed but the hidden
lines will flash on and off. Construct a movie in which one of the 'star's from
chapter 12 appears to rotate .

Scrolling (16K and 48K machines)

Using machine-code for more complicated tasks requires a great deal more
thought and study . A good book on the subject and preferably one specifically
written for the Spectrum should be consulted (see Zaks, 1978 ; Hutty, 1981 ;
Woods, 1983). For those who wish to pursue more complex manipulations of
the screen in machine-code we give one more example. (Listing 13.6 scrolls the
graphics display area downwards. The fact that the display-file data are split into
lines of 32 bytes causes problems. To effectively move these data around we need
the start addresses of these lines. To calculate the addresses in a machine-code
routine requires a lot of programming effort and slows down the execution.
Instead we use a look-up table. For machine-code purposes an address is made
up of sixteen bits that are stored in two eight-bit locations, the lo-byte and the
hi-byte . Whenever we need to know the address of a line we simply look up its
two halves from the tables. We use BASIC to calculate the tables and to POKE
them into memory . These tables and the machine-code itself could be saved on
tape and reloaded if required . Listing 13.6 gives the machine-code program,
BASIC loader and table constructer. Listing 13.7 shows an equivalent BASIC
routine for the program. Note that the BASIC routine assumes the existence of
the same table used by the machine-code.

Exercise 13.3
Write a machine-code routine that moves the attribute file around the memory,
one row at a time. Then write a BASIC program that calls your routine each
time the graphics area has been scrolled down by eight lines.

BASIC Structure (Renumber and Delete)

The development of modular programs often leads to situations where routines


are cramped and there is no room for extra lines or alterations. At times like these
we would like to renumber the lines automatically or perhaps delete whole
sections. These two utility commands are also useful when MERG(E)ing pro-
grams in order to create new routines. To perform these tasks we must take a
closer look at the way our BASIC programs are stored in the computer memory.
BASIC programs are stored line by line in memory starting at address 23755.
Advanced Programming Techniques 213

Listing 13.6
1111 REM Loader for machine-code routine
2111 CLEAR 31999
3111 FOR I = 0 TO 74
4fJ READ A: POKE 32011l11l+I,A
50 NEXT I

1011l REM downwards wrap-around scroLL for graphics area


1111l DATA 1,175,0 REM LD BC,175
120 DATA 221,33,75,125 REM LD IX,LOBYTE
1311l DATA 221,9 RE~l ADD IX,BC
14fJ DATA 221,1111l,0 REM LD L,[IX+I1!J
150 DATA 221,33,251,125 REM LD IX,HIBYTE
16111 DATA 221,9 REM ADD IX,BC
1711l DATA 221,111l2,0 REM LD H,[IX+I1!J
180 DATA 17,171,126 REM LD DE, TEMP
190 DATA 21115,67,125 REM CALL MOV E
2011l DATA 221,33,75,125 REM LD IX, LOBYTE
2111l DATA 221,9 REM ADD IX,BC
220 DATA 221,94,0 REM LD E,[IX+0J
23111 DATA 221,1111l,-1 REM LD L,[IX-1J
24fJ DATA 221,33,251,125 REM LD IX,HIBYTE
250 DATA 221,9 RE~' ADD IX,BC
26111 DATA 221,86,0 REM LD D,[IX+0J
2711l DATA 221,111l2,-1 REM LD H, [ I X- 1 J
28111 DATA 205,67,125 REM CALL MOVE
290 DATA 13 REM DEC C
311l11l DATA 32,226 REM JR NZ,LINE
3111l DATA 17,0,64 REM LD DE,16384
320 DATA 33,171,126 REM LD HL,TEMP
3311l DATA 21115,67,125 REM CALL MOVE
34fJ DATA 201 REM RET
350 DATA 197 REM PUSH BC
360 DATA 1,32,0 REM LD BC,32
37111 DATA 237,176 REM LDIR
380 DATA 193 REM POP BC
390 DATA 201 REM RET

4011l REM construct tabLes of dispLay-fiLe Line addresses


41111 FOR I = 0 TO 21: FOR J =0 TO 7
420 LET A = 16384 + INT (1/8)*2048 + (I - INT (1/8)*8)*32
430 LET H = INT (A/256): LET L = A - H*256
44fJ POKE 32075 + 1*8 + J,L: POKE 32251 + 1*8 + J,H + J
450 NEXT J: NEXT I

5011l REM main program


510 LIST 380
520 IF INKEY$ <> .... THEN LET A = USR 32011l11l
530 GO TO 520

The first item stored for each line is the line number (16 bits), which takes up
two locations and is stored as the hi-byte followed by the lo-byte. In all other
places values are stored in the standard lo-hi format. To illustrate suppose we
enter the line 10 REM. If we type

PRINT PEEK 23755, PEEK 23756


214 Advanced Graphics with the Sinclair ZX Spectrum

Listing 13. 7

10 REM basic version of scroLL for graphics area


20 CLEAR 31999
30 GO TO 400
100 REM downwards wrap-around scroLL for graphics area
110 LET C = 175: LET B = 0: LET BC = C + B*256
120 LET IXLO = 75: LET IXHI = 125: LET IX = IXLO + IXHI*256
130 LET IX = IX + BC
14llJ
LET L = PEEK (IX + 1/))
150 LET IXLO = 251: LET IXHI = 125: LET IX = IXLO + IXHI*256
160 LET IX = IX + BC
170 LET H = PEEK (IX + 0): LET HL = L + H*256
180 LET E = 171: LET 0 = 126: LET DE = E + 0*256
190 GO SUB 350
200 LET IXLO = 75: LET IXHI = 125: LET IX = IXLO + IXHI*256
210 LET IX = IX + BC
220 LET E = PEEK (IX + 0)
230 LET L = PEEK (IX - 1)
240 LET IXLO = 251: LET IXHI = 125: LET IX = IXLO + IXHI*256
250 LET IX = IX + BC
260 LET 0 = PEEK (IX + 0): LET DE = E + 0*256
270 LET H = PEEK (IX - 1): LET HL = L + H*256
280 GO SUB 350
290 LET C = C - 1: LET BC = C + B*256
300 IF C <> i'l THEN GO TO 200
310 LET E = 0: LET 0 = 64: LET DE = E + 256*0
320 LET L = 171: LET H = 126: LET HL = L + H*256L
330 GO SUB 350
34llJ
RETURN
350 LET S= BC
360 LET BC = 32
370 LET A = PEEK HL: POKE OE,A: LET DE = DE + 1: LET HL = HL + 1
: LET BC = BC - 1: IF BC <> 0 THEN GO TO 370
380 LET BC = S
390 RETURN

400 REM construct tabLes of dispLay-fiLe Line addresses


410 FOR 1=0 TO 21: FOR J = 0 TO 7
420 LET A = 16384 + INT (1/8)*2048 + (I - INT (1/8)*8)*32
430 LET H = INT (A/256): LET L = A - H*256
440 POKE 32075 + 1*8 + J,L: POKE 32251 + 1*8 + J,H + J
450 NEXT J: NEXT I
500 REM main program
510 LIST 380
520 IF INKEY$ <> "" THEN GO SUB 1i'l0
530 GO TO 520

we shall see that 0, 10 is stored in these locations. If we remove line 10 and enter
another numbered line at the start of the program, we see that the representation
of this new number is now stored in 23755 and 23756. The next two bytes give
the length of the present line (this can be used to find the start of the next pro-
gram line without traversing the whole of the present line). Now comes the
actual text of the BASIC line, each character or keyword taking up one memory
location. The end of the line is marked by a CODE 13 (or ENTER). After any
number given in decimal notation and stored as characters there is a CODE 14
Advanced Programming Techniques 215

(or NUMBER: see page 183 of the Spectrum BASIC Handbook (Vickers, 1982))
followed by a binary translation of the number, taking five bytes . Integers are
stored in a simple way, as explained on page 163 of the Spectrum BASICHand-
book (Vickers, 1982). Using this information about the contents of the memory
we can write a program that lists programs, including itself, by examining the
memory. This type of listing program (listing 13.8) can be of great assistance when
formatting listings in which statements all start on a new line, or when control
CODES need to be displayed.

Listing 13.8
H'lfl REM s e Lf- List i ng program
110 LET I = 23755: CLS
120 LET LINE = 256*PEEK I + PEEK (I + 1): IF LINE > 9999.5 THEN STOP
130 PRINT" " ; LI NE;
140 LET I = I + 2: PRINT PAPER 5;PEEK I;",";PEEK ( I + 1);" " ;
150 LET LENGTH = PEEK I + 256*PEEK (I + 1)
160 LET NUM = =
0: LET I I + 1
170 FOR J = 1 TO LENGTH: LET I = I + 1
180 LET P = PEEK I: IF P < 32 AND NUM <= 0 THEN LET NUM = 1
1W IF P = 13 THEN PRINT PAPER 4;P: PRINT: GO TO 230
200 IF P = 14 THEN LET NUM = 6
210 IF NUM > 0 THEN PRINT PAPER 6;P;",";: GO TO 230
220 PRINT CHR$ P;
230 LET NUM = NUM - 1
240 NEXT J
250 LET I = I + 1: GO TO 1 20

In order to renumber lines we need to change the line numbers stored in the
memory. This is true as long as the lines do not get out of numerical sequence.
Unfortunately this does not take into account GO TO or GO SUB, etc ., com-
mands. We must search out all GO SUB, GO TO, RESTORE and RUN keywords
in the program and, if they are followed by a simple integer, check whether the
line number has been changed . If it has, then both the numeric characters of the
number and the integer representation of the number must be altered. To delete
a range of lines all we have to do is extend the length of the line before the un-
wanted range, so that it completely covers the unwanted area. The correct length
of the line is re-established on editing and re-entering this line. The remainder of
the program is moved down through the store to continue from where the line
now ends. Listing 13.9 gives two routines that perform these tasks; the renumber
routine is entered by RUN 9900 and the delete routine by RUN 9970.

Exercise 13.4
Write a routine that can search through the BASIC memory and find any specified
sequence of CODEs. Use the method shown in the above delete program to set
the system variable E PPC (which controls the edit cursor : see page 174 of the
Spectrum BASIC Handbook (Vickers, 1982)) to the number of the line where
the sequence is found.
216 Advanced Graphics with the Sinclair ZX Spectrum

Listing 13.9

990fJ INPUT " Renumber Li nes "; LOW;" To " ; UP, " St a r t i ng a t "; NEW;
" in steps of " ; STEP
9901 LET X = 990fJ: I F LOW > X OR UP > X OR LOW > UP THEN GO TO 990fJ
9902 IF NEW > X OR NEW < 1 OR STEP> X OR STEP < 1 THEN GO TO 990fJ
990 3 PRI NT AT 19 , 0;"Renumbe r Li nes ";LOW;" t o " ;U P,"Sta r t irg at " ; NEW ;
" i n ste ps of " ; STEP, " PLease wai t"
9904 L ET START = 23755 : LET SCREEN = 163 84: LET HI = 256
9905 LET A = START: LET B = SCREEN
9906 LET H = PEEK A: LET L = PEEK (A + 1)
9907 POKE B,H: POKE B + 1,L
9908 LET A = A + 2: LET B = B + 2
9909 LET L EN = PEEK A + PEEK ( A + 1) *H I: LET A = A + LEN + 2
9910 IF H*HI + L < X THEN GO TO 9906
9911 LET A = START : LET B = SCREEN: LET W = NEW
9912 LET H = PEEK A: LET L = PEE K (A + 1)
9913 LET N = HI*H + L: IF N < LOW OR N > UP THEN GO TO 991 8
9914 IF W > X THEN GO TO 9955
9915 LET H = INT (W/HI): LET L = W - H*HI
9916 POKE A,H: POKE A + 1,L
991 7 LET W = W + STEP
9918 LET A = A + 2
9919 LET LEN = PEEK A + PEE K (A + 1)*HI: LET A = A + LEN + 2
9920 IF N < X THEN GO TO 9912
9921 LET A = START: L ET B = SCREEN
99 22 LET H = PEE K A: LET L = PEEK ( A + 1): LET NN = PEEK B*HI + PEEK (B + 1)
9923 LET N = H*HI + L: IF N = X THEN STOP
992 4 PRINT AT 21,0 ;"Ch e c king " ; NN; " = new Line ";N
992 5 L ET A = A + 2 : LET W = A + 2
9926 LET LEN = PEEK A + PEEK (A + 1) *HI: L ET A = A + LEN + 2
9927 L ET T = PEE K W
99 28 IF T = CODE (" GO TO " ) OR T = COD E (" GO SUB " ) OR T = CODE ( " RUN ")
OR T = CODE (" RESTORE ") THEN GO SUB 99 3 2
9929 IF T = 14 THEN L ET W = W + 5
9930 LET W W + 1: IF W < A THEN GO TO 9927
9931 LET B B + 2 : GO TO 9922
993 2 L ET V W + 1: LET A$ =
9933 L ET S PEE K V: IF S <> 32 AND S <> 14 AND NOT (S >=4 8 AND S<=5 7 )
THEN RETURN
9934 IF S <> 14 THEN LET V = V + 1: LET A$ = A$ + CHR$ S: GO TC 993 3
993 5 LET V = V + 3 : LET AT = PEEK V + PEEK ( V + 1)*HI
993 6 IF AT < L OW OR AT > UP THEN RETURN
9937 GO SUB 9943 : LET H = IN T (NAT/HI): LET L = NAT - H*HI
99 3 8 LET B$ = STR$ NAT: IF LEN A$ <> LEN B$ THEN GOSUB 9951
9939 PO KE V,L : POKE V+1,H
99 40 FOR I = 1 TO LEN B$
9941 POKE W + I, CODE B$(I ): NEXT I
994 2 RETURN
9943 LET C START: LET 0= SCREEN
99 44 LET H = PEEK 0 : LET L = PEEK (0 + 1)
99 45 LET E = PEEK C *HI + PEEK (C + 1)
9946 IF E >= X THEN LET NAT = 0: RETURN
9947 IF H* HI + L = AT THEN LET NAT = E: RETURN
99 48 LET C = C + 2 : LET C = 0 + 2
9949 LET L EN = PEEK C + PEEK ( C + 1 ) *HI: LET C C + LEN + 2
9950 GO TO 994 4
99 51 LET 01 FF = LEN A$ - L EN B$
9952 IF DIFF > e THEN FOR I = 1 TO DIFF: LET B$ = B$ + " ": NEXT I: RETURN
9953 PRINT AT 16 , 0 ; "No r oom at " ; CHR$ T;AT;" i n Line '; ; NN,
"t ype edi t and add " ; - DI FF; " spa ce(s)","to LabeL th en re-run pr ogram."
9954 L ET H = I NT ( NN/ HI ) : POKE 23 6 26 , H: POKE 236 25,NN- H*HI
Advanced Programming Techniques 217

9955 LET A = START: LET 8 = SCREEN


9956 LET H = PEEK A: LET L = PEEK (A+1)
9957 IF H*HI + L = X THEN PRINT AT 0,0;"Renumber aborted" : STOP
9958 POKE A, PEEK B: POKE A+1, PEEK (8 + 1)
9959 LET A = A + 2: LET 8 = 8 + 2
9960 LET LEN = PEEK A + PEEK (A + 1 )*HI: LET A = A + LEN + 2
9961 GO TO 9956
9971'l INPUT "Delete l ;nes ";LO~I; " to " ; UP: IF LOW < 2 OR LOW >= UP
THEN GO TO 9970
<; 971 PRINT AT 20,0;"Delete l ;r,es ";LOW;" to ";UP,"Please wait"
9972 LET START = 23755: LET SCREEN = 16384: LET HI = 256
9973 LET A " START: LET 8 = SCREEN
9974 L~T H = PEEK A: LET L = PEEK (A + 1)
9975 IF H*HI + L >= LOW THEN PRINT AT 0,0;"Please enter line ";
LO~I-1; " REt" ","and re-run prograrr": STOP
9976 LET H = PEEK A: LET L = PEEK (A + 1)
9977 IF H*H I + L >= LOW THEN GO TO 9981
9978 LET NN = H*HI +L: LET LAST = A: LET A= A +2
9979 LET La! = PEEK A + PEEK (A + 1)*HI: LET P = A + LEN + 2
9980 GO TO 9976
9981 LET LAST = LAST + 2
9982 LET LONG = PEEK LAST + PEEK (LAST + 1) *H I
9983 IF H*HI + L > UP THEN PRINT AT ~,0;"No l i ne s in r anqe"; STOP
9984 LET H = PEEK A: LET L = PEEK (A + 1): IF H*HI + L = UP THEN GO TO 9990
9985 LET A = A + 2: LET LONG = LOtJG + 2
Sc9 86 LET LEN = PEEK A + PEEK (A + 1 )*HI: LET A = A + LEN + 2
: LET LONG = LONG + LEN + 2
9987 IF H*HI + L <> UP THEN GO TO 9984
9990 LET H = INT (LONG/HI): POKE LAST + 1,H: POKE LAST,LONG - H*HI
9995 LET H = INT (NN/HI): POKE 23626,H: POKE 23625,NN-H*HI
9999 PRINT AT 0,0;"type ed i t and enter": STOP

BASIC Structure (Efficient Programs)

When programming in BASIC we can use our knowledge of the way lines are
stored to help make our programs more efficient, both in terms of space used
and speed of execution. Every occurrence of an explicit number is followed by
six bytes of number codes so that the conversion from a string of digits to its
binary form need not be performed each time the line is entered. If instead we
assign the required number to a variable, and use the variable name for each
occurrence of the value, then the space required would be only the number of
bytes in the variable name. To assign the value we must use three extra codes ":",
"LET" and "=", as well as the variable name, and to access the value we must use
the variable name. If the value is used often then this method will save consider-
able space. As an example consider the first two statements in the following
program

10 PRINT AT 1,1
20 LET A = 1: PRINT AT A,A
30 PRINT AT 1,1
40 PRINT AT A,A
218 Advanced Graphics with the SinclairZX Spectrum

The BASIC text of line 10 requires 17 bytes of store: "PRINT", " AT", "1",
14,0,0,1 ,0,0, ", ", "1",14 ,0,0,1,0,0.
Line 20 requires 16 bytes of store : " LET", "A", "=", "1", 14,0,0, 1,0,0,
":", "PRINT", "AT", "A", ",", "A" .
The second line above has fewer codes than the first line. However, the
second line uses the variable A, which, unless it is used elsewhere, will take up
six bytes of memory . If we need to repeat the statements, as shown above in lines
30 and 40, we find that line 30 is 17 bytes long but line 40 is only 5 bytes long.
So if we use a numeric value more than a couple of times in a program , we can
make large savings by using a variable to represent the value.
We can also save space and improve speed by packing as many statements as
possible on to one line, although this reduces legibility . Each new line requires
five bytes of memory: one for the CODE 13 at the end of the previous line, two
for the new line number and two for the length of the line. A colon between
statements needs only one byte . The space saved can be quite large. For example,
consider a program with 90 statements (quite small on average): if the state-
ments are initially all on separate lines and we rewrite with 3 statements per line,
we can save 60*(5 - 1) = 240 bytes . In a large program it is quite feasible to save
over 1K of memory in this way. Using fewer lines also makes it easier for the
machine to obey GO TO or GO SUB commands, as it will take less time to search
for the destination line. To be most efficient all SUBroutines and FuNctions
should be near the start of a program and arranged so that the most frequently
used come first. Unless very many calls are made to the same routine, it is usually
more convenient to store the routines in a logical order.

Exercise13.5
Rewrite and reposition the graphics routines and/or the games programs to use
less space and if possible run faster.

Synchronous Display

When displaying pictures on the Spectrum we can use the PAUSE command to
provide an interesting BORDER display. The television display is completely re-
drawn every 1/50th of a second (l/60th in the U.S.A.) and PAUSE uses multiples
of this same time interval. When PAUSE I is used the delay is not always a com-
plete 50th of a second. In fact the PAUSE will last only until the start of the
next frame. This gives us a method of starting instructions at a fixed time relative
to each refresh of the display. If we change the BORDER colour partway
through the drawing of the display, then for that frame the top part only of the
BORDER will be one colour and the remainder will be another colour. Obviously
we could use PAUSE to wait for the start of the next frame and repeat the pro-
cess. This results in the display of a steady picture provided we keep repeating
the same actions. The SAVE and LOAD statements use a machine-code routine
Advanced Programming Techniques 219

to do an equivalent process , which is how the red/cyan and yellow/blue patterns


are produced on the BORDER .
Consider the following start of a large program

1 GO TO 10
2 PAUSE 1: BORDER 7: BORDER 2 : BORDER 6: BORDER 4:
BORDER 5 : BORDER 1 : BORDER 3: BORDER 7: GO TO 2

The program terminates with a GO TO 2 command that produces a rainbow


effect on the BORDER after the construction of a diagram. Note that, unless the
line is placed near the top of the program , the GO TO statement will take so
long to execute that we shall miss the start of the next frame .

Exercise 13.6
Write a one-line program that alternates between red and cyan BORDER colours
without using PAUSE. Insert extra colons (no other statements - just colons)
between the statements until the execution time for the line is exactly 1/50th
(or 1/60th) of a second; that is, the two colours are stationary. (Hint: count a
BORDER command as 10, a GO TO as 13 and a colon as 1; try to make the total
value of the line, counted in this way, about 160.)

Complete Programs

I. Listing 13.1 . Data required : 10 sets of X/Y coordinate pairs. The screen
shows a zeroed table of these values, followed by "End." . A cursor , which
points to the first row, can be moved down by Capital "6" and up by
Capital "7 ". When you are at the required row, type "EDIT" (Capital
"1 ") and the machine requests the pixel X/Y coordinates for that entry in
the table . When you have finished move the cursor to "End.", then EDIT
and type " y"(es). The program will then draw a polygon by joining the
10 coordinate points.
II. Listing 13.2. Data required: numeric key input for mythical me system.
Type" 1" to "6". For "5" or "6" the machine checks if you really mean it :
type "y"(es) or "n"(o). BREAK terminates program.
III . Listing 13.3. No data required: BREAK terminates program.
IV. Listing 13.4 . Type any key on request. No data required: BREAK termin-
ates .program .
V. Listing 13.5. After the BEEP, program requires five pictures to be loaded
from tape . Type "1 ", "2", "3", "4" or "5" for instant display of required
frame, 'm' for 'movie ' and's' to stop movie.
VI. Listing 13.6. When screen is full, hold down any key for scroll to continue .
BREAK to stop .
220 Advanced Graphics with the SinclairZX Spectrum

VII. Listing 13.7. BASICversion of VI. Very slow!


VIII. Listing 13.8. No data required. .
IX. Listings 13.7 and 13.9. Type RUN 9900 for Renumber and RUN 9970 for
Delete. Example data: editing listing 13.7

RUN 9900
Renumber lines 10 to 30
Starting at 60 in steps of 5

Now LIST program to see changes

RUN 9970
Delete lines 60 to 99

Halt : there must be at least one line in front of section to be deleted

RUN 9970
Delete lines 65 to 99
EDIT (Capital "1")
LIST
14 A Worked Example of a Video
Game

In th is chapter we examine the limits of BASIC programming for animated video


games. We have found that games written in BASIC are expensive, and in general
the players' interest short-lived . If users can achieve a reasonable result them-
selves then they far prefer to write their own simple video games, and spend
their money only on sophisticated games written in machine-code. Listing 14.1
is an example of the sort of game that most competent BASIC programmers can
reasonably expect to write, without resorting to machine-code routines. The
game, ISLAND DEFENCE (48K machines only) , is a typical 'shoot-em up' game,
but the techniques we discuss could just as easily be applied to 'bat and ball'
(for example , TENNIS) or ' tactical' games (for example , PAC MAN).

Outline of the Game

On the screen we draw a scene of a green island with a small hill, dark blue sea,
and a light blue sky containing a yellow sun and white cloud. There are three
trees , and a light blue concrete area on which a tent is drawn. A man comes out
of the tent and walks to a sandbagged gun emplacement, where he gives 20
bullets to the gunner and returns to the tent. Enemy aeroplanes appear out of
the sun , fly over the hill and bomb the camp ; the gunner defends the camp by
firing at the aeroplanes. At every attack, the aeroplane is either disabled or makes
a successful hit on the camp. With each successful hit the size of the tent dimin-
ishes. After 14 hits the tent disappears, and the next plane bombs the gun. On
destruction of the gun the BORDER of the screen goes haywire and the scene is
reset. After each bombing run, the plane flies through the cloud, over the gun
and exits stage left. The stock of ammunition is replenished after 20 planes have
completed their runs. After the gun has been bombed for the third time the
screen goes blood red and the whole game starts again.
The gun has seven firing positions specified by keys" 1" to " 7", and a missile
is fired by pressing "x". Because of speed restrictions only one plane and one
missile can appear on the screen at any given time.
For you to make the most of the explanations in this chapt er we advise you
to get the companion cassette tape , and LOAD and RUN listing 14.1. The pro-
222 Advanced Graphics with the Sinclair ZX Spectrum

Listing 14.1

9 REM i ni t i a Lise routines to aLLow use of aLternate character set.


10 CLEAR 62294: INK 0: PAPER 7: BORDER 7: FLASH 0
20 DIM S(6): FOR 1=1 TO 6: READ SCI): NEXT I
30 DATA 15360,62039,62807,63575, 64343,64848
40 LET set = 50: LET S = 1: GO SUB set: GO TO 200

50 REM set/change to set S


51 REM IN : S
60 LET HI = INT (S(S)/256): LET LO = S(S) - HI*256
70 POKE 23606,LO: POKE 23607,HI: RETURN
79 REM Load in game cha ra ct ers for set 2.
80 REM cha r Load
90 LET N$ = "gameset "
100 LET S = 2
110 INPUT (" LOADING" + N$ + CHR$ 6 + "St a r t tape, then press enter.")
; LINE X$
120 LOAD N$ CODE (S(S) + 256),768: RETURN

200 REM main program


209 REM i nit i a Lise var iabLes point ing to routines.
210 LET cha r Load 80: LET Load = 4600: LET create 5000
: LET cr edit 5500: LET char = 5600
220 LET keyboard 500: . LET camp = 700: LET status 800: LET pLane 980
230 LET reLoad = 1500: LET amm o = 1900: LET missi Le = 2200
: LET expLode = 2500
240 LET bombcamp = 3500: LET bombgun = 3000: LET hiscore 5700: LET HSC 0
249 REM if character set i s not in pLace Load it.
250 IF PEE K 62303 <> 110 THEN GO SUB char Load
258 REM Load backgr ound, crea te chara cters for fueL dump,
259 REM pr i nt names on bottom two Line s.
260 GO SUB Load: GO SUB create: GO SUB credi t
269 REM make a copy of coLour att ributes for screen.
270 DIM A(704): FOR 1=1 TO 704: LET A(I) = PEEK (22527 + I): NE XT I
279 REM prepare str i ngs for use by dispLay rout ines.
280 LET S$ =" SCORE ": LET B$ =" BASE
290 FOR I = 1 TO 4: LET S$ = S$ + CHR$ 8: LET B$ = B$ + CHR$ 8: NEXT I
300 DIM N$(9): LET N$=" ABCDEFGI"

309 REM start/restart for gam e.


310 BRIGHT 1; PAPER 8: INK 8: OVER 0
319 REM reset SCore and no. of BaSes, pr i nt out score Line
320 LET SC = 0: LET BS = 3: GO SUB status
329 REM remove remaining ammun it ion and remove fLash from gunners square.
330 PRINT AT 17,5;" ": PRINT AT 18,5;" ": PRINT AT 16,3;" "
339 REM restore coLour attributes from copy.
340 FOR I = 1 TO 704: POKE 22527+I,A(I): NEXT I
349 REM pri nt new tent and gunner, update score Line, reLoad ammunition.
350 GO SUB camp: GO SUB status: GO SUB reLoad
358 REM prepare for main Loop of program set 'p' to top of 'pLane' ca scade .
359 REM set 'm' to 'miss iLe' ready state, set 'k' to keyboard rout ine.
360 LET P = pLane: LET m = missiLe: LET k = keyboard
369 REM start a new wave of 20 AiRpLanes.
370 LET AR = 20
379 REM start of main Loop
380 GO SUB p: OVER 1: GO SUB m: OVER 0 : GO SUB k
389 REM jump out of Loop.
390 IF DEAD TH EN GO TO 420
399 REM i f more airpLanes to come keep Looping.
A Worked Example ofa Video Game 223

41Hl IF AR > 0 THEN GO TO 380


409 REM if end of pLanes then reLoad and st a r t new wave, continue Looping.
410 GO SUB reLoad: GO TO 370
419 REM make sure pLane is gone, if you have any bases Left use the next one.
420 INK 0: PRINT AT 12,0 ;" ": IF BS > 1 THEN LET BS = BS - 1: GO TO 350
429 REM game over so fLash border and turn screen bLood red.
430 OVER 1: FOR I = 1 TO 22: BEEP 0.005,RND*30-1 5: BORDER RND*7
44fil FOR J = 1 TO 2: PLOT 0,(22-1)*8: DRAW BRIGHT 1; PAPER 2; INK 2; 255,0
450 NEXT J: NEXT I: BORDER 7
460 OVER 0

469 REM check whether you beat the HiSCore then restart game.
470 IF SC > HSC THEN GO SUB hiscore
480 PAUSE 200: GO TO 310

500 REM keyboard


509 REM if no key pressed when routine checks then you missed your chance.
510 LET A$ = INKEY$: IF A$ = "" THEN RETURN
518 REM the fire key i s pressed:-
519 REM if you're not out of missiLes and a miss iLe is ready then fi re .
520 IF A$="X" OR A$="x " THEN IF m = missi Le AND NOT OUT THEN LET m = f
: LET M$ = F$: GO SUB ammo: OVER 1: GO SUB m: OVER 0: GO TO 550
529 REM i f the key is not '1' to '7' then wrong key press, i gnor e it.
530 IF A$ > "7" OR A$ < "1" THEN RETURN
538 REM caLcuLate which routine i s used if missile i s fired i n th is direction.
539 REM set string wh ich is used for miss iLe and change gun direction.
54fil LET f = 2000 + 10*VAL A$: LET F$ = CHR$ (83 + VAL A$)
550 PRINT AT 16,3;F$
560 RETURN
700 REM camp
709 REM print new gunner and tent, reset border to white.
710 PRINT AT 17,3;"z": BRIGHT 0: BORDER 7: PRINT AT 16,23;"vw"
: PRINT AT 17,23; "xy": BRIGHT 1
718 REM set height of tent to 14, reset truth-fLags,
719 REM use keyboard rotuine to initiaL ise gun position.
720 LET YT = 14: LET HIT = 0: LET DEAD = 0: LET A$ = "3" : GO TO 540
800 REM status
809 REM use set 1 to print out score and no. of bases Left then back to set 2.
810 LET S = 1 : GO SUB set
820 PRINT AT 21,0;S$;SC,B$;BS
830 LET S = 2: GO SUB set
840 RETURN
980 REM pLane
989 REM ensure that 'bombgun' pointer aLways starts at top of cascade.
990 PRINT AT 13,5;" ": PRINT AT 15,4;" ": PRINT AT 17,3;"z"
: LET bombgun = 3000
999 REM change pointer, if resuLt is over 1000 then pLane wiLL be Launched.
1000 LET p = 991 + INT (RND*11):RETURN
1009 REM Launch ai rcraft, start pointe r going down cascade, Load bomb.
1010 LET AR = AR - 1: LET p = 1020: LET BO!'ll 1: RETURN
1019 REM move pLane one pLace to right.
1020 PRINT AT R,C;" IJ": LET C = C + 1: IF C < HI THEN RETURN
1029 REM if pLane is over 10 co Lumns onto screen move pointer down.
1030 LET p =1040
1039 REM diagonaL dive.
1040 PRINT AT R-1,C;" ": PRINT AT R,C;" N": LET R R + 1: LET C C + 1
: PRINT AT R,C;"n": IF C < 20 THEN' RETURN
224 Advanced Graphics with the Sinclair ZX Spectrum

1 049 REM if ove r 20 columns across t h e n mov e pointer, r e mov e l e ft ov er p l a ne.


1050 LET P =1 06 0 : PRINT AT R- 1 , Ci " "
1059 REM call the ' bo mbc amp' cascade e a ch of t h e fiv e t i me s t h i s s ec t ion is used.
1060 GO SUB bo mbc a mp: PRINT AT R,C;" IJ": LET C = C + 1: IF C < 2 5 THEN RETURN
106 9 REM mOve pointe r do wn and s t a rt cu rv e up t owards c l o ud .
1070 LET p =1080
10 80 PRINT AT R, Ci " ": L ET R = R - 1: LET C = C + 1: PR INT AT R,Ci" KL"
: IF C < 28 THEN RETURN
1090 LET p =11 011l : PRIN T AT R, Ci" " : LET C = C + 1
11 0 11l P RI NT AT R+1 , C;" ": PRI NT AT R, C; "o" : LET R = R - 1
: PR I NT AT R,C ; "O": IF R > 7 THEN RETUR N
11111l LET p =1120 : PRINT AT R+1, C;" "
1120 PRINT AT R,C;" " : LET R = R - 1: LET C = C - 1: PRINT AT R,Ci"kl "
: IF R > 3 THEN RETUR N
1130 LET p =11 40
113 9 REM fl y i nto cloud , plane still mov es no rmally but you can ' t s ee it .
1140 PR INT AT R, C; " i j " : LET C = C - 1 : IF C > 11 THEN RETURN
11 50 LET p =1 160: PR I NT AT R,C;"
1159 REM st a rt d ive t owar ds g unne r .
11 60 PRINT AT R,Ci" ": LET R = R + 1: LET C = C - 1: PRINT AT R,C;"M"
: PRIN T AT R+1, C;"m ": IF R < 6 THEN RETURN
11 70 LET P =1 1 80
11 80 PRIN T AT R,C i" " : LET R = R + 1: PR IN T AT R, C;"P": PRINT AT R+1 ,C i"P "
: IF R < 8 THEN RETURN
1189 REM t h ir d s e ct i o n of d ive check and e ras e possible l eft ove r mi s si le .
1190 LET P =1 2011l: IF X <> 9 AND Y <> 7 THEN PR IN T AT 7, 9i " "
1 2011l PRINT AT R,C;" " : LET R = R + 1: LET C = C - 1: P RINT AT R,C;"M "
: PRINT AT R+1,Ci "m": IF R < 11 THEN RETURN
1210 LET P =1220 : PRINT AT R,C;" " : LET R = R + 1
1 21 9 REM la st s ec tion of fl igh t , c all bombgun cas c a de each ti me .
1220 GO SUB bombgun : LET C = C - 1 : PR I NT AT R, Ci" i j " : IF C > 0 THEN RETUR N
1 2 29 REM last t wo pa rts of cascade d e al with p l a ne going of screen .
1 23 0 LET p =1 240: PR INT AT R, C; " j " : RETURN
1 23 9 REM r e s e t p lane ' s Row to 2 an d set poi nt e r back t o t o p o f ca s c a de .
1 240 PRINT AT R,C ; " ": LET R = 2: LET p = plane
1250 RETURN

1 5011l REM r e l oa d
150 9 REM if th e camp is de s t r oy e d t he n don t re loa d a mmun i t i o n
1510 IF HIT THEN RETURN
1519 REM e xplic it i n s t r u c t ion s f or a nimat i on o f f i g u r e .
1 520 BRIGHT 0: LET R = 1 8
15 2 9 REM wal k fr om tent to trees.
1 530 FOR C = 24 TO 19 STEP -1: PR INT AT R,Ci"S ": PRINT AT R+1,C i"S"
: BEEP 0 .0 1,-15: PAUSE 5
1 5 40 PRI NT AT R,C;"R ": PR I NT AT R+1,Ci"r ": PAUSE 3
1 550 PRINT AT R,C;" ": PRI NT AT R+1,C;" ": NEXT C
1559 REM u s e ov er- p rint i ng s o tha t trees aren't da mage d as figure get s clo s e.
1560 OVER 1: PRINT AT R,18;"S": PRINT AT R+1,18; "s": BEEP 0.01,-15: PAUSE 5
: PRINT AT R,18;"S": PRINT AT R+1,18;"s"
157 11l PRINT AT R,18i" R": PRINT AT R+1,18i"r ": PAUSE 3
: PRI NT AT R,18i"R ": PRIN T AT R+1,18i"r "
1579 REM make noi ses as t h o ugh fi gur e goe s behind t r e e .
15 80 FOR J = 1 TO 2: BEEP 0.0 1,-15: PAUSE 11: NEXT J
15 89 REM s ho w feet e mer gin g from be h i nd tree.
1590 PRINT AT R+1,15;"s": BEEP 0.01,-15 : PAUSE 5 : PRINT AT R+1,15;"s "
16011l PRINT AT R+1,15i"r": PAUSE 3: PRIN T AT R+1,15i"r "
16 09 REM s how whole fi g ure co mi ng o ut o f tree.
1612) PRINT AT R,14i"S" : PRINT AT R+1,14i"S": BEEP 0.01,-15: PAUSE 5
: PRINT AT R,14i"S": PRINT AT R+1,14i"S"
1620 PRINT AT R,14i"R": PRINT AT R+1,14i"r": PAUSE 3
: PRINT AT R,14i"R": PRINT AT R+1,14i"r"
A Worked Example ofa Video Game 225

1629 REM wal k from tree to end of str ip, onto grass at column 8 with bright on.
1630 OVER 0: FOR C = 1 3 TO 8 STEP -1: BRIG HT CC = 8)
1640 PRINT AT R,Ci"S ": PRINT AT R+1,Ci"S": BEEP 0.01,-15: PAUSE 5
1650 PR INT AT R,Ci "R": PRINT AT R+1,Ci"r": PAUSE 3
16 6 0 PRI NT AT R,Ci" " : PRINT AT R+1,Ci " " : NEXT C
166 9 REM pr i nt fig u r e a t co l umn 7 r eady t o refil l amm o dump.
1670 PRINT AT R, Ci " R" : P RI NT AT R+1,Ci "r"
1679 REM r efil l ammo d ump, wi th s o un d ef f e ct s.
16 80 FOR G = 6 TO 5 STEP - 1: FOR H = 18 TO 17 STEP - 1: FOR N 2 TO 9
16911l PR IN T AT H,G i INK 3 i N$ CN) : BEEP 0.0 2,H+G -N
1700 NEXT N: NEXT H: NEXT G
1709 REM remove figure f r om co lumn 7 .
1710 PRINT AT R, Ci " ": PRINT AT R+1,Ci" "
17 19 REM r e s et ammun it i on pr int and truth flags.
1720 LET N = 8: LET OUT = 0: L ET H = 17: LET G = 6
1729 REM wal k from e n d o f s t ri p to tr ee, br ight off after column 8.
17 30 FOR C = 8 TO 13 : BRIGHT CC = 8)
1740 PRINT AT R,Ci")": PRINT AT R+1,Ci"+": BEEP 0.01,-15: PAUSE 5
1750 PRINT AT R,Ci "C" : PRINT AT R+1,Ci"*": PAUSE 3
1760 PRINT AT R,C i" ": PRINT AT R+1,Ci" ": NEXT C
1769 REM o v er- p r i nt as f i gu re r ea ch e s tree.
1770 OVER 1: PRIN T AT R,14i")": PRINT AT R+1,14i"+": BEEP 0.01,-15: PAUSE 5
: PRINT AT R,14i" )": PRINT AT R+1,14i "+ "
17 80 PR INT AT R,14i"C": PRINT AT R+1,14i"* ": PAUSE 3
: PRINT AT R,14 i"C ": PRINT AT R+1,14i"* "
1789 REM ove r p r int legs as t hey go int o t ree.
1790 PR INT AT R+1,15i" +": BEEP 0.01,-15 : PAUSE 5: PRINT AT R+1,15i"+"
1 800 PRINT AT R+1,15 i"*": PAUSE 3 : PRINT AT R+1,1 5i "*"
1 809 REM make no ises a s th ough f igur e i s be h i nd tree.
1 810 FOR J = 1 TO 2: BEEP 0.01,-15: PAUSE 11: NEXT J
1 819 REM ove rp rint as fi gu re emerge s f r o m tree.
1820 PRI NT AT R,1 8; ")": PRIN T AT R+1,18;"+": BEEP 0.01,-15: PAUSE 5
: PR I NT AT R,18i" )": P RIN T AT R+1,18i"+"
1 83 0 PRINT AT R,18; " C": PR INT AT R+1,1 8i"* ": PAUSE 3
: PRINT AT R,18i " C": PR IN T AT R+1 ,18i " * "
183 9 REM wa l k fro m t ree to te nt.
1 84 0 OVER 0 : FOR C = 19 TO 24: PR INT AT R, Ci") ": PRINT AT R+1,C i"+"
: BEEP 0.0 1,-1 5: PAUSE 5
1 850 PRINT AT R,Ci"C ": PRINT AT R+1,Ci "*": PAUSE 3
1860 PRINT AT R,Ci" " : PRINT AT R+1,Ci" " : NEXT C
186 9 REM r eset Row a nd Co lumn f or u se by plane rout ine.
1 870 LET C = =
0: LET R 2 : B RIGHT 1
1880 RETURN

REM ammo/ pr i nt mi ss i l e dump


191110
191112
REM OUT: OUT
191119
REM t ake o ne of ammunition dump and check whether out of ammo.
1910 PRINT AT H,GiN$(N): LET N = N - 1
1920 IF N = 0 THEN LET N 8: LET H = H + 1: IF H = 19 THEN LET H = 17
: LET G = G - 1: IF G = 4 THEN LET OUT = 1
1930 RETURN

2000 REM missile d irect ions


2009 REM remove o ld miss ile by overpr int ing and calculate new posit ion.
2010 PRINT AT Y,XiM$: LET Y Y - 3: LET X = X - 2: GO TO 2100
2020 PRINT AT Y,XiM$ : LET Y Y - 3: LET X = X - 1: GO TO 2100
2030 PRINT AT Y,XiM$: LET Y Y - 3 : GO TO 2100
2040 PRINT AT Y,XiM$: LET Y Y - 3: LET X X + 1 : GO TO 2100
2050 PRINT AT Y,XiM$: LET Y Y - 3: LET X X + 2: GO TO 2100
2060 PRINT AT Y,XiM$: LET Y Y - 2: LET X X + 2 : GO TO 2100
2070 PRINT AT Y,XiM$: LET Y Y - 2: LET X X + 3: GO TO 2100
226 Advanced Graphics with the Sinclair ZX Spectrum

2098 REM if missile is on same column as plane check for being near row of plane.
2099 REM if missile is close enough explode and reset missile to ready.
2100 IF X C THEN IF ABS (Y - R) < 2 THEN GO SUB explode: LET m = missile
: GO TO m
2109 REM if missile is off screen then reset pointer 'm' to ready.
2110 IF X < 0 OR Y < 0 THEN LET m = missile: GO TO m
2119 REM print missile at new position.
2120 PRINT AT Y,X;M$: RETURN
2200 REM missile/ready to fire
2210 LET X = 3: LET Y = 16
2220 RETURN
2500 REM explode
2508 REM missile has hit plane so blow up plane and add to score.
2509 REM check whether explosion has taken place in cloud or in sky.
2510 OVER 0: LET SKY = (R <> 3 OR C < 16) .
: IF NOT SKY THEN PRINT AT R,C-1;"
2519 REM cent ral flash and low buzz, add to score for hitting plane.
2520 INK 2: IF SKY THEN PRINT AT R,C;"t"
2530 FOR 1=1 TO 5: BEEP 0.01,1 - 10: BEEP 0.01,-1 - 10: NEXT I: LET SC SC + ,
2539 REM if explosion is seen then print cloud of debr is.
254lil IF SKY TH EN PR INT AT R-1, C-1 ; ">@<": PR INT AT R,C-1 ; "$! &"
: PRINT AT R+1 ,C-1 ;":%;"
2549 REM high pitched whizz.
2550 FOR I = -4 TO 4: BEEP 0.002,(50 + ASS I): NEXT I
2559 REM remove all trace of explosion.
2560 INK 0: IF SKY THEN PRINT AT R-1 ,C-1;" ": PRINT AT R,C-1;"
: PRINT AT R+1 ,C-1;" "
2569 REM print out new score l ine, reset plane and missile pointers.
2570 INK 8: GO SUB status: LET m = missile: LET p = plane
2580 LET R = 2: LET C = 0
2590 RETURN

3000 REM bomb gun


3009 REM if camp isn't destroyed or plane hasn't got a bomb left then don't drop.
3010 IF NOT HIT OR NOT BOf13 THEN RETURN
3019 REM place bomb on screen and start pointer down cascade.
3020 PRINT AT 13,5;".": LET bombgun = 3030: RETURN
3030 PRINT AT 13,5;" ": PRINT AT 15,4;".": LET bombgun = 304lil: RETURN
304lil PRINT AT 15,4;" ": PRINT AT 17,3;".": LET bombgun = 3050: RETURN
3050 PRINT AT 17,3; FLASH 1;" ": LET bombgun = 3060: RETURN
3059 REM cLear plane away, make sure any missiles shoot off the screen.
3060 PRINT AT 12,0;" ": OVER 1: FOR I = 1 TO 7: GO SUB m : NEXT I
3069 REM flash border and make exploding noises.
3070 FOR I = 1 TO 50: BORDER RND*7: BEEP 0.01,RND*30 - 15: NEXT I
3078 REM set flag for end of gunner.
3079 REM set ink to sky-blue subsequent movement of plane is invisible.
3080 LET DEAD = 1: OVER 0: INK 5
3089 REM reset cascade.
3090 LET bombgun = 3000: RETURN
3500 REM bomb camp
3509 REM if the camp has gone save bomb for the gunner.
3510 IF HIT THEN RETURN
3519 REM mark bomb as dropped and start cascade.
3520 LET BOf13 = 0: PRINT AT 14,21;".": LET bombcamp = 3530: RETURN
3530 PRINT AT 14,21;" ": PRINT AT 15,22; BRIGHT 0;".": LET bombcamp 354lil
: RETURN
A Worked Example ofa Video Game 227

3540 BRIGHT 0 : PRINT AT 15,22;" "


3549 REM explode tent.
3550 PRINT AT 16,23; OVER 1; INK 2;"1$"
3560 PRINT AT 17,23; OVER 1; INK 2; "%&"
3570 LET bombcamp = 3580: BRIGHT 1: RETURN
3579 REM remove explos ion from tent.
3580 BRIGHT 0: PRINT AT 16,23; OVER 1; INK 0;"1$"
3590 PRINT AT 17,23; OVER 1; INK 0;"%&"
3600 LET bombcamp = 3610: BRIGHT 1: RETURN
3609 REM remove top remaining line of tent.
3610 PLOT I NVERSE 1;184,33 + YT : DRAW INVERSE 1;16,0
3619 REM check whether tent is gone and reset bombcamp cascade.
3620 LET bombcamp = 3500: LET YT = YT -1: LET HIT = (YT = 0)
3630 RETURN
4600 REM load
4609 REM load picture from tape .
4610 LET NS = "background"
4620 INPUT (" LOADING" + NS + CHRS 6 + "Start tape, then press enter. ")
; LINE XS
4630 LOAD (NS)SCREENS
4640 RETURN
5000 REM create/characters
5009 REM make characters for ammo dump in user defined graph ics set.
5010 LET D = 255
5020 FOR I = 0 TO 6: FOR J = 0 TO 7
5030 LET P = USR "G" - 1*8 + J
5040 IF J > I POKE P,D
5070 NEXT J: NEXT I
5080 RETURN
5500 REM credit
5509 REM pr i nt on bottom t wo lines.
5510 DEF FN S(R,C) = 16384 + INT (R/8)*2048 + (R - INT(R/8)*8)*32 + C
5520 DEF FN C(AS) = 15360 + CODE AS*8
5530 LET R 22: LET AS = "]/ISLAND DEFENCE/[ BY BJJ & lOA"
5540 FOR J 1 TO LEN AS: LET C = J - 1: GOSUB char: NEXT J
5550 LET R 23: LET AS =" HI-SCORE SCORED BY BJJ
5560 FOR J 1 TO LEN AS: LET C = J - 1: GOSUB char: NEXT J
5570 RETURN
5600 REM char
5609 REM pr i nt j I th character of as at r,c,
change attr ibute t o red paper and wh ite i nk, beep.
5610 LET AT = FN S(R,C): LET FROM = FN C(AS(J»
5620 FOR I = 0 TO 7: POKE AT + 1*256, PEEK (FROM + I): NEXT
5630 POKE 22528 + C + R*32,87: BEEP 0.03, CODE AS(J)-50
5640 RETURN

5700 REM hiscore


5709 REM change hi-score and print it on bottom of screen.
5710 LET HSC = SC: LET AS = STRS HSC
5720 LET R = 23: FOR J = 1 TO LEN AS: LET C = 10 + J: GOSUB char: NEXT J
5729 REM change name to flash ing letters.
5730 FOR I = 23291 TO 23293: POKE I,PEEK I + 128: NEXT I
5739 REM get thr ee i ni ti a Ls f or hiscore from key board.
5740 LET J = 1 : FOR C = 27 TO 29
5750 IF INKE YS <> "" THEN GO TO 5750
5760 IF INKE YS = " " THEN GO TO 5760
5770 LET PS = INKE YS: GO SUB char : NE XT
5780 RETURN
228 Advanced Graphics with the Sinclair ZX Spectrum

gram will ask you to LOAD first the special character set , 'gameset' (for drawing
the plane, tent, man, etc.), and then the 'background' (which sets the scene),
before starting the action . The listing is well documented, so there is no need
for us to go into too much detail here. We shall simply outline a general approach
for constructing these games, and describe methods of solving typical problems
that arise.

The Foreground

It is essential to carefully plan your game before you start writing the program.
You must first draw a rough plan of the proposed game scene on graph paper .
Then sketch in the positions of fixed objects (for example, the sun and clouds)
and also the areas to be traversed by moving objects (for example, the path of
character blocks that at some time will contain characters to make up the planes).
This should fIX the scale of the objects to be used, and will give a general impres-
sion of the final game. Time spent in careful planning at this stage will be a
fraction of that needed to adjust a nearly completed program . You must ensure
that the proposed display can actually fit into the graphics area, and that you
never get a situation where a moving object introduces a third colour within a
character block. Once you have decided on a screen layout, you must then
create the objects for the foreground (for example, explosions , the plane , the
man) - that is, the moving parts. The fastest BASIC command for putting a
large object on the screen is the PRINT statement. So we build our objects out
of defmed character blocks, and use the CHARACTER GENERATOR program
of chapter 5 to produce the required shapes. To get exactly the shape you want
for a display, you should repeatedly examine the characters at their normal size
and re-edit them if you are not satisfied . It may be helpful to add parts of your
game-program at the end of the CHARACTER GENERATOR program (option
7, see chapter 5). This will allow you to observe these objects in action while
their final form is still under consideration.

Exercise 14.1
Add an extra option to the CHARACTER GENERATOR program so that you
can edit a single character from within a group. This option should POKE the
eight BINary values of the character grid being edited, together with the other
characters in the group , into the display-file locations for specified positions on
the screen; for example, the two blocks that make up the plane in horizontal
flight to the right (see figure 14.1). This quickly allows you to evaluate the
merits of altering one pixel within a character.
A Worked Example ofa Video Game 229

Figure 14.1

The Background

The background is now created using a combination of the CHARACTER


GENERATOR and the diagram-construction routines from chapter 6. You first
add large character blocks of colour using 'paper' for rectangular areas that
approximate to large parts of the scene (for example, grass, sky, sun, etc .). Then
superimpose the initial detail by PRINTing special characters (for example , the
trees, sandbags, and the edges of the sun, grass and clouds etc.). This can be given
final touches with the 'point' and 'line' options of the diagram routines. For
example, the trees are made by adding lines and dots to the foreground explosion
characters. We can expand the range of colours by allowing BRIGHT as well as
normal colours. Special care must be taken when constructing blocks through
which moving objects will pass. They must contain only one background colour
with no detail. Remember that only two colours are allowed in anyone block,
and there is always a danger that a moving object could introduce a third colour.
In our background (see figure 14.2) there are two particular places where care is
needed.

(1) The planes pass over and behind a cloud on their return run , so the cloud
contains a path of white blocks through its middle . Note that blue sky and white
cloud cannot occur within the same character block on the path of the plane, so
the boundary between sky and cloud on this path must be a straight edge. The
plane actually disappears behind the cloud during its flight, so some of the
blocks in this path contain white INK and white PAPER. Thus when the plane
230 Advanced Graphics with the Sinclair ZX Spectrum

enters this block the INK pixels take on the same white colour as the PAPER
and the plane is indistinguishable from the cloud.
(2) The sun, which appears to be a smooth circle, has flat edges on each side.
The planes pass through one of these edges without encountering a combination
of sun and sky within one block. This is shown in close-up in figure 14.1, which
was created with the aid of the 'big pixels ' routine of listing 5.2. This diagram
ignores the true attributes of the blocks; it colours INK in black and PAPER in
white. The true colours can be ascertained from the 1/16th scale picture drawn
in the top left-hand comer. Naturally those character blocks in the scene that
remain constant throughout the game can contain two colours .

Figure 14.2

Cascade Animation

Once we have stored this first approximation of the background on tape, we


need to write the routines that will position and move the foreground objects
about the screen. Since we are aiming at speed of execution we must make
these routines as explicit as possible. We need to minimise the amount of calcu-
lation required while the game is being played. Any extra programming or
calculation, however long, which, if done prior to the play would save precious
milliseconds during the play, should be implemented. We describe one such
technique in our example program, the popular cascade, or variable entry point
method. The timewise-important routines in the program are referred to by a
variable pointer (an identifier given in lower case). These routines are made up
of a chain (or cascade) of explicitly programmed subtasks, only one of which
A Worked Example ofa Video Game 231

will be undertaken on each separate entry to the routine. The solution to each
subtask is laid out as a set of lines, after which the pointer to that routine is
altered and we return to the calling program. On re-entry, the program naturally
obeys a different section of code within that routine , usually the pointer changes
to the next subtask down the cascade . With each call, this process continues with
the pointer moving down through the sections of the cascade until it eventually
reaches the bottom (where it will usually be reset to the top). The complete game
will consist of an initialisation phase followed by a loop of calls to routines, each
of which is a cascade that solves a specific problem within the game (for example ,
to move the aeroplane or to bomb the base). Cascade routines may even call
other cascades! This gives an impression of a parallel process, which is essential
if users are to believe that they are playing a game in which a number of different
events are happening simultaneously. In our game we try to give the impression
that the plane, gun and missiles can all move independently.
Our game is a little too complicated to be an elementary illustration of this
technique, so we introduce another, very much simpler, game (available on 16K
machines as well) . Consider the following two programs that perform indepen-
dent functions. Listing 14.2 waits until a key is pressed then shoots a dot across
the screen; listing 14.3 continuously moves a plus sign up the screen in a zig-zag
pattern. Both programs use the fast animation techniques found in the ISLAND
DEFENCE program ; however , because each is so small, it is necessary to slow
them down with a PAUSE command (note that excess speed is only a problem
when programs are very simple) . From these listings we create two cascade
routines (listing 14.4) so that the dot and cross appear to move simultaneously.
The dot cascade is in three parts : (a) place a dot at row 11, column 0; (b) if
the user hits the keyboard then start the dot moving; and (c) move the dot one
column farther across the screen until it hits the right-hand edge. Whenever one
of these processes is flnished the identifier of the routine 'dot' is moved down to
the next section. After the dot has moved right across the screen, 'dot' is reset
to the start position.
The cross cascade is also in three parts : (a) place the cross at row 22, column
8; (b) move the cross one row up and diagonally to the right on the bottom half
of the screen ; and (c) move one row up and diagonally to the left in the top
half, and if the dot and cross lie in the same block, then SPLAT.
The two routines are turned into a game by a main routine that loops repeat-
edly through calls to 'dot' and 'cross', where, of course, these identifiers are
perpetually changing so that they each refer to the correct part of their cascade.

Listing 14.2
20rl REM dot
210 PRINT AT 11,0;"."
220 IF INKEYS = "" THEN GO TO 220
230 LET 0 =0
2"" PRINT AT 11,0;': ":LET 0 =0 + 1
250 IF 0 = 32 THEN GO TO 210
260 PRINT AT 11,0;"."
270 PAUSE 1: GO TO 2""
232 Advanced Graphics with the Sinclair ZX Spectrum

Listing 14.3
3erl REM cross
311'1 LET R =21: LET C 8 =
321'1 PRINT AT R,C;"+"
331'1 PRINT AT R,C;" ":LET R = R - 1
3411 IF R < e THEN GO TO 311'1
350 IF R > 11 THEN LET C = C + 1
360 IF R <= 11 THEN LET C = C - 1
370 PRINT AT R,C;"+"
380 PAUSE 1: GO TO 330

Listing 14.4
10rl REM main loop
110 LET dot =
200: LET cross = 300
120 GO SUB dot: GO SUB cross
131'1 GO TO 120

200 REM dot cascade


210 PRINT AT 11,0;". ": LET dot = 220: RETURN

220 IF INKEY$ = "" THEN RETURN


230 LET 0 = 0: LET dot = 2411: RETURN

2411 PRINT AT 11,0;" " : L ET 0 = 0 + 1


250 IF 0 = 32 THEN LET dot = 210: RETURN
260 PRINT AT 11,0;"."
270 RETURN

30rl REM cross cascade


310 LET R = 21: LET C = 8
320 PRINT AT R,C;"+": LET cross = 330: RETURN

330 PRINT AT R,C;" ":LET R = R - 1


3411 LET C = C + 1
350 PRINT AT R, C; "+"
360 IF R > 11 THEN RETURN
370 LET cross =
380: RETURN

380 IF R =
11 AND C =
0 THEN PRINT AT R,C;"SPLAT": STOP
390 PRINT AT R,C;" ":LET R R - 1 =
4110 IF R < 0 THEN LET cross = 310: RETURN
410 LET C =
C- 1
420 PRINT AT R, C; "+"
431'1 RETURN

Exercise 14.2
Add a line to the calling loop of the above program so that after a SPLAT the
pointers to the top of the cascades are reset and the score (number of hits)
printed.
Write a 'duck shoot' game where a hunter , under keyboard control, moves
left and right at the bottom of the screen . He shoots at ducks that fly left to right,
up and down, across the screen.
A Worked Example ofa Video Game 233

Further Animation Techniques

With such a simple game we find that the saving,in time and programming
effort, from using the cascade technique is very small. However in larger pro-
grams, which can have complicated cascade programs (for example , the move-
ment of the plane in ISLAND DEFENCE), the time savings can make the
difference between a good fast game and a boring slow one. Note that there are
eight different sets of character blocks that describe the plane; see figure 14.2,
which shows the complete scene and one example of each plane, as well as other
foreground objects. The cascade for drawing the plane is divided into sections,
each of which places one type of plane in a particular area of the screen.
In this game we show a variety of different ways of solving the problems of
animation. The planes are moved by printing them in transparent INK, and then
obliterated from their previous positions with blanks. The missile characters are
OVERprinted (again with transparent INK) on the existing detail and then
erased at their last position by OVERprinting with the same character. These
methods have both advantages and disadvantages. Where removal of the old
position can be combined with the print ing at the new (see the sections where
the plane flies horizontally) you will find that normal PRINting often takes less
time , but it does mean you lose any detail in the background . OVERprinting
takes longer, but leaves detail undamaged. Using a combination of these tech-
niques in a program can cause problems if two moving objects pass simultaneously
through the same block : for example , what happens if a square containing a
missile is blanked out by a passing plane? This can occur in the game at character
block row 7, column 9. The effect is that the OVERprinted missile, which is
supposed to cancel out the old one, is left hanging in mid-air. Discretion is the
better part of valour and it is far better (timewise) to check for these problems
and explicitly program a cover-up, rather than add complexity into your algor-
ithm and perhaps even introduce another fault. The plane cascade contains an
ext ra statement (at line 1190), which ensures that any such mishap is swiftly
covered. When trying to remove faults , remember that a brute-force cover-up
will probably be far quicker (in your time, and running time) than a fancy fault-
avoidance routine. Although you should have foreseen most problems in the
planning stage, and adjusted the background and the paths of moving objects ,
some peculiarities are certain to occur .
There are two places where we have shown an object apparently passing
behind a background object. In order that a plane can vanish behind the cloud,
we simply made the INK white in those blocks where the plane was to disappear.
Since a white plane in a white cloud is about as easy to spot as a black cat in a
coal-cellar at midnight , we are tricked into thinking that the plane is hidden by
the cloud. For the man marching behind the tree, the whole problem becomes
more complicated. We still wish to see the tree in two colours when he is behind
it . The trick this time is to make the man walk up to the tree normally ; OVER-
print him when he is in the same block as outer foliage, and then simply make
234 Advanced Graphics with the SinclairZX Spectrum

marching noises, without printing, for the appropriate length of time, before
starting him off again from the other side of the tree. His legs must also reappear
from behind the tree one block before his head when he is moving right, and
equivalently when moving left. All these details must be carefully calculated
before even writing the flrst line of BASIC code .
A combination of these techniques for moving objects, making an allowance
for them to pass each other, will enable you to produce displays of very high
quality . Of course you must use machine-code routines if you require really fast
and complex games. Even so, many of the routines can still be in BASIC. There
is no need to produce programs written completely in machine-code unless you
want to sell your games.
Finally, as your games programs become more and more interwoven and
cross-connected, you must keep a simple overview of the program . Note what
tasks need to be done at the top level, use sensible variable names , put in plenty
of comments during development, and above all, don't panic!
We leave you now with your Spectrum. It has proved reliable and sturdy,
straightforward and easy to use. We are certain that you will have many, many
hours (years!) of pleasure out of this machine . To start you off we give a number
of ideas for projects in the next section . Good luck and good programming.

Complete Programs

I. Listing 14.1: the ISLAND DEFENCE game. We do recommend that you


obtain the tape because you will find it time-consuming setting up the
special character set and background. However, you should at some time
create such character sets and backgrounds yourself.
II. Listing 14.2 ('doC). Type any key.
III. Listing 14.3 ('cross ') : no data required.
IV. Listing 14.4 ('main program', 'dot cascade' and 'cross cascade'). Type any
key .
15 Projects

I. Use you r Spectrum to draw a digital clock. Use the special large characters for
the digits and a colon to separate them. Your clock can be made to keep correct
time by using the internal clock of the Spectrum (see page 130 of the Spectrum
BASIC Handbook (Vickers, 1982)).

II. Make a program that tests the Morse Code proficiency of the user. The con-
tent for the program should be a paragraph of text ; after translating into Morse,
the Spectrum should print out the dots and dashes using the medium-resolution
character blocks. It should also use BEEP to simulate the sound of Morse. Your
program should have a variable rate of production of the Morse Code, so that the
speed of the test can increase as the user becomes more proficient.

III. Draw a set of international road signs. Your program should draw the back-
ground of the figures (for example , red triangles); then use your own special
routines or the programs of chapters 5 and 6 to finish off the foreground.

IV. Construct crossword puzzles on your television set. Each square of the puzzle
should be 2 by 2 character blocks. The four blocks can be either black (in which
case nothing goes in the square) , or white , with the bottom left-hand corner hold-
ing the letter of a solution and the top two characters the clue number (if any) .
This allows space for a 16 by 11 puzzle.
As you have also to place the clues on the screen, there will obviously be a
shortage of space . This problem can be solved by using the ideas of the 'slide
show' of chapter 13; put the puzzle in one frame, and the clues on the remaining
four frames. Solutions to the puzzle can be added by a 'cursor' method or by
having a special input code ; for example, letter "A" (across) or "D" (down)
followed by the number of the clue, followed by your solution. If you make the
puzzle smaller you could even have the option of using this code to bring clues
on to the screen one at a time (or perhaps place them in rows 23 and 24), in
which case the crossword need not be moved off the screen.

V. The Spectrum BASIC Handbook (Vickers, 1982) gives a program to draw the
Union flag. Write programs or use the character generator and the diagram
routines (chapters 5 and 6) to produce other flags. You can draw company logos,
or even design new ones. Use the techniques in chapter 13 for accessing display-
236 Advanced Graphics with the SinclairZX Spectrum

me locations to add an extra option to the diagram routines. This option allows
you to copy a set of character blocks (already on the screen and specified by
'cursor') on to another set of blocks of the same size elsewhere on the screen
(also specified by 'cursor'). You.could even rotate or reflect them!

VI. The Spectrum BASICHandbook (Vickers, 1982) shows how to use BEEP
to create music(?). While BEEP is making the sounds, you can draw the musical
notation on the screen. Construct the staves and then use special characters to
place quavers, minims, etc. on the screen. The old music hall method of the
'bouncing ball' could be used to beat the time of the tune .

VII. Use the character block method to draw mazes. Naturally your program
must generate mazes with real solutions. Give yourself time limits for getting
through the maze. You can make the mazes dynamic, so that they change as the
game progresses. Add extra problems : man-eating monsters that roam the maze ;
holes that suddenly appear and can swallow you up: 'space warps' that can
transfer you anywhere in the maze if you do not move fast enough .

VIII. Extend the ideas of chapter 6 . Draw your own special histograms , pie-
charts and graphs. Make them dynamic (either by the 'movie' method of chapter
13, or the 'worm game' method of chapter 1, and its extended form in chapter
14). Generate whole sets of special characters. Create (apparent) three-dimen-
sional histograms by drawing every bar in three different-coloured sections. The
height of the front section of each bar must be a whole number of character
blocks and two character blocks wide. A side section is one block wide, the
same height as the first section, with a triangular hat filling the bottom-right half
of a block. The third section lies above the first section and is in the shape of a
rhombus that touches the first two sections. This ensures that there are never
more than two colours in any character block, and makes the bar look like an
orthographic view of a rectangular block .

IX. Create patterns. Use OVER with large numbers of random lines about the
screen. Or draw lines in a dense but regular way to get Moire patterns. For
example, draw lines joining the points (0 , I) to (255, 175 - I) for 0 ~ I ~ 175,
and points (1,0) to (255 - I, 175) for 0 ~ I ~ 255. Extend the ideas of the pat-
tern program of chapter 5 to produce complex symmetrical patterns - any
introductory book on crystallography (for example, see Phillips, 1956) will
give you lots of ideas.

X. The crystallography books (for example , Phillips, 1956) will give you many
ideas for three-dimensional objects. Extend into four dimensions - vertices are
simply a vector of four numbers and they require 5 X 5 matrices for transforma-
tions. For an orthographic projection of a four-dimensional point, we simply
ignore two of the coordinates (as opposed to one, z, in three dimensions). What
are translation, scale and rotation in four dimensions?
Projects 237

XI. We have already presented two board games, Chess and Master Mind. There
are many more possibilities : draughts (or checkers), Scrabble, Hangman, ludo.
You can create a compendium of games. The Spectrum can simply act as the
board, or it can also be a referee . If you feel really adventurous it can even act
as an opponent.

XII . Use special characters to construct a deck of playing cards. These can be
incorporated into a program to play blackjack (or pontoon) with the Spectrum
acting as the bank and opponent.

XIII. You can draw certain types of brain-teasers on your television. For ex-.
ample, suppose you have nine squares and each is divided into quarters down
the diagonals. Each quarter has a colour (blue "1", red "2", magenta "3" and
green "4") and a sign ("+" or "-"). We represent each square as a sequence of
four numbers that denote the areas taken clockwise around the centre . For
example , we could have (-1, -2, 1,4), (-1,3,4, -2), (1, -4, -2, 3), (1,2,
-- 3, -4), (1,3, -2 , -4), (1,4, -3, -2), (2, - 3, -4, 3) and two occurrences of
(-1, -4 ,3,2). The problem is to place the nine squares in a three-by-three
arrangement, so that if two quarters on neighbouring squares touch, then they
must be of the same colour but of opposite sign. You can use the Spectrum to
draw the squares initially on the left side of the screen and a three-by-three grid
of the same sizes on the right. Then you'take squares from the left and place
them in the grid, or replace them back to the left.
Write a program to find a solution of the above problem - it takes about 10
minutes to run, and finds two independent solutions .

XIV. Produce a medium-resolution graphics package for manipulating 2 X 2


quarter blocks. This package should be similar to the one we gave for character
blocks in chapter 5. The screen thus consists of 64 by 44 quarter blocks. Take a
photograph of yourself and superimpose a grid of 64 by 44 on it. For each
square, decide whether it is mainly light or dark, and colour the corresponding
quarter block accordingly . This seems like a lot of work; but note that most of
the picture will be a light background, so if we use white PAPER and black INK
most of the squares need not be considered . Since a head measures more in height
than it does in breadth, you can get greater resolution if you draw the head side-
ways on the screen . You could draw two heads side by side on the screen.

XV. Write a PAC MAN type of video game. This involves drawing five moving
objects on the screen at a time. In order to make the game move faster, allow
only two of the ghosts to move with each move of PAC MAN. The ghosts should
find the shortest path towards the player when they are in hunting mode, and the
best escape route in running mode. Because of the complex layout of the screen,
you will have to compromise . Simply move towards (or away from) the player if
there is no wall in the way. Find a quick way of coding their movements as this
will be the most time -consuming part of the game. Speed is the essence of a
238 Advanced Graphics with the SinclairZX Spectrum

good video game. Perhaps a simple machine-code routine could be used to print
all five figures on the screen after altering their 'PRINT AT' positions.

XVI. Write a program that first (OVER)prints a graphics menu of special symbols
on the left-hand side of the screen; for example, the stylised components for
electronic circuits (resistors, capacitors, etc .). These symbols should consist of
groups of character blocks. Use a cursor to point at any menu-symbol and then
(using OVER) drag a copy ofit to a required position on the screen. Also add a
facility for drawing connecting lines and labelling with thin numeric and special
characters (for example, n for ohms). You should also allow deletion of symbols
inadvertently placed in the wrong position. Extra options could include saving
and loading, as well as deleting the menu from the final diagram.

XVII. In all our perspective diagrams it is assumed that the objects lie totally
in front of the eye. Change our programs so that they deal with the general
case where vertices may be behind the eye. See Newman and Sproull (1973)
concerning this three-dimensional clipping.
Appendix A Implementing Programs
on the 16K Spectrum

Over 7K of this machine is used for the display and attribute ftles and for
system variables. This automatically limits the size of programs and data to
about 8.8K. Many of the programs given in this book far exceed this value,
although most will run if the reader obeys the following proposals.

(1) Delete all REMarks from the tape listings and any unused routines from
library ftles (for example, 'plot' and possibly 'scale') before MERG(E)ing the
routines. Also follow the hints given in chapter 13 for optimising the program
code . For example, the program for drawing the jet (listings 'lib 1" 'lib3' and
'9.9') will just fit into the store if the REMs, 'scale' and 'plot' are deleted.
(2) It is possible that there will not be enough store for the four alternative
character sets (sets 2 to 5) and the User-Defined Graphics set (set 6). If there is
enough store the address table for the six sets (set I is the standard set) should
hold the values 15360,29271,30039,30807,31575 and 32080 respectively. It
is possible that the use of sets with the lower addresses could corrupt your pro-
gram and data, or even crash the computer. Use only the sets that do not
interfere with the store! The CLEAR statement found at the beginning of pro-
grams that use alternate characters must be changed from CLEAR 62294 to
CLEAR 255 + the address of the lowest set available (greater than 1). You will
fmd that the CHARACTER GENERATOR program does not have enough space
for set 2, and in this case we must CLEAR 255 + 30039. If you have a program
that requires set 2 then create these characters as set 5 (say), store it on tape, and
load it into your program, which must, of course , have space for set 2.
(3) You can break down programs into non-interdependent parts and store the
pictures and/or data produced by them on tape. These ftles may be reloaded in
conjunction with the other programs for further manipulation; for example, the
diagram constructions of chapter 6. You should LOAD 'Iibdiag' and MERGE one
of the histogram, pie-chart, graph or picture-editing programs. When you run the
program you must remember not to attempt to use routines that are not cur-
rently in memory. You can SAVE and LOAD the intermediate pictures using the
SCREEN$ option, and arrays using the DATA option. You can then LOAD the
picture-editing routines to finish off your diagrams.
(4) Unfortunately, some programs will not fit into 8.8K of memory whatever is
240 Advanced Graphics with the Sinclair ZX Spectrum

done; these are the general hidden line algorithm for non-trivial objects, the
movie program and the ISLAND DEFENCE game. If you are serious about
studying computer graphics on the Spectrum we would strongly advise you to
buy the 32K expansion for your machine .
Appendix B BASIC Program Listings

We now give a list of the BASIC program listings stored on the companion audio-
cassette tape . These routines are in the form necessary for running on the 48K
version ofthe Spectrum. Most of them need no changes in order to run on a
16K machine. However , if you have this type of machine you should check the
REMarks in listings given in the book for any changes, and read appendix A.
'movie', the five frames 'sphere 1'to 'sphereS' and ISLAND DEFENCE are the
only routines that are 48 K specific . You will find that with chapter 6 you have
to LOAD 'libdiag' and MERGE just one of '6.8 ', '6 .9', '6.10 &11' and '6.12' in
order for it to fit in the store. Should you need more than one type of data
graph on the screen at anyone time, you must intermediately SAVE picture on
tape and reLOAD the screen after a new program has been created.

SIDE 1
FileName Contents
directory 1
lib 1 Listings 2.1 ,2.2,2.3,2.4,2.8 and 3.3 ;
routines for mapping two-dimensional Euclidean space on to
graphics area.
2 .9 Listing 2.9;joining points of regular N-gon.
2.12 Example of envelope.
2.13 Spirograph.
3 .1 Square inside square inside square etc.
lib2 Listings 3.4, 4.1a, 4.2a, 4.3a, 4.4a, 4.5, 4 .6;
routines for matrix manipulation of two-dimensional space.
4.10 Construction of a general ellipse.
44.12
.11} Construction and view of four 'space ships'.
7.1 Point of intersection of line and plane in three-dimensional
space.
7.2 Point of intersection of two lines in three-dimensional space.
7.3&4 Example of dot and vector product.
7.5 Inverse of a 3 X 3 matrix.
7.6 Point of intersection of three planes in three-dimensional space.
7.7 Line of intersection of two planes in three-dimensional space.
lib3 Listings 3.4, 9.1,9 .2 and efficient rewrites of 8.1,8.2,8.3 and
8.4; routines for matrix manipulation of three-dimensionallspace.
242 Advanced Graphics with the ZX Spectrum

8.5&6 Rotation of point about a general axis of rotation .


9.6&7&8 scene3, construction and drawit routines ;
necessary for drawing an orthographic view of two cubes.
9.9 Additional routines for drawing the jet (orthographic).
9.10&11 Routines for constructing an orthographic body of revolution .
10.1 Orientation of a three-dimensional triangle.
9.3&10.2 scene3 and hidden surface routine for drawing a cube .
10.3 Hidden surface routine for drawing a convex body of revolu-
tion.
0.1 Construction routine for a flying saucer(!).
10.4 Hidden surface routine for drawing a mathematical surface.
11.1&2 Perspective view of two cubes.
12.1 General hidden line algorithm.
12.2 Hidden line perspective view of two cubes.
12.3&4 Construction routines for cub octahedron and icosahedron.
12.5&6&7 Construction routines for two stars, and a scene3 routine .
movie Program for displaying five frames in quick succession.

:~~:;:~}
sphere3 Five frames needed to make a movie of a rotating sphere.
sphere4
sphereS

SIDE 2
FileName Contents
directory 2
delete }
Utilities from listing 13.9.
renumber
5.5 The CHARACTER GENERA TOR.
5.4 Main program for simple tessellated patterns.
libdiag Listings 6.1,6.4,6 .6 ; support routines for diagram construc-
tion.
6.2 'paper' and 'ink'.
6.3 'point' and 'line'.
6.5&7 'label', 'thin' and 'create'
6.8 Histogram routine/type 1
6.9 Histogram routine/type 2
6.10&11 Pie-chart and hatching routines .
6.12 Scientific graph routine.
thin3 Characters stored in set 3 and used to make thin characters.
thin4 Characters stored in set 4 and used to make thin characters.
1.16 The WORM GAME.
5.6 MASTER MIND program.
masterset Characters needed by MASTER MIND program.
5.7 The Chess board program .
Appendix B BASIC Program Listings 243

chesspiece Character set holding the chess pieces.


14.1 ISLAND DEFENCE game.
gameset Character set needed for ISLAND DEFENCE.
background Scenery for the game.
1.4 Fractal program.
1.5 OVER patterns.
5.1 Displaying the binary construction of a given chracter.
5.2 The big pixels program .
5.3 Constructing a graphics character from eight binary numbers.
13.1 Menu input for 10 vertices of a polygon .
13.6 Scrolling of screen with wrap around: in machine-code.
13.7 Same as 13.6, but written in BASIC.
13.8 Program that lists itself, giving all numeric codes .
14.4 Simple cascade program : SPLAT.
References and Further Reading

References

Ahl, D. H. (Ed.) (1980). Basic Computer Games. Workman Publishing Co., New
York
Bain, G. (1972). Celtic Art: The Methods of Construction, 2nd edition.
Maclellan, Glasgow
Cohn, P. M. (1961). Solid Geometry . Routledge and Kegan Paul, London
Coxeter, H. S. M. (1974). Regular Polytopes . Dover Publications, New York
Davenport, H. (1952). The Higher Arithmetic . Hutchinson, London
Finkbeiner, D. T. (1978). Introduction to Matrices and Linear Transformations,
3rd edition. W. H. Freeman, San Francisco
Horowitz, E. and Sahni, S. (1976). Fundamentals ofData Structures. Pitman,
London
Hurley , R. (1982). More Real Applications for the ZX81 and the ZX Spectrum.
Macmillan, London
Hutty, R . (1981). Z80 Assembly Language Programming for Students, 2nd
edition. Macmillan, London
Knuth, D. (1972,1973,1981). The Art of Computer Programming. Volume 1:
Fundamental Algorithms, 2nd edition, 1973. Volume 2: Semi-numerical
Algorithms, 2nd edition, 1981. Volume 3: Sorting and Searching , 1972.
Addison-Wesley, London
Liffick , B. W. (1979). The BYTE Book ofPascal. Byte Publications, New
Hampshire
Mandelbrot, B. B. (1977). Fractals. W. H. Freeman, San Francisco
McCrae, W. H. (1953). Analytical Geometry of Three Dimensions. Oliver and
Boyd,London
Newman, W. M. and Sproull, R. F. (1973). Principles ofInteractive Computer
Graphics. McGraw-Hill, London
Phillips, F. C. (1956). An Introduction to Crystallography, 2nd edition.
Longmans, London
Stroud, K. A. (1982). Engineering Mathematics , 2nd edition. Macmillan , London
Tolansky, S. (1964). Optical Illusions, Pergamon, New York
Vickers, S. (1982). Sinclair ZX Spectrum: Basic Programming. Sinclair Research,
Cambridge
References and Further Reading 245

Woods, T. (1983). Assembly Language Assembled - For the Sinclair ZX81 .


Macmillan, London
Zaks, R. (1978). Programming the Z80. Sybex, Berkeley, California

Further Reading

Read any periodical, magazine or journal relevant to computer graphics, such as


SIGGRAPH , CADCAM, CAD journal (and there are many, many more), and the
more advanced graphics textbooks (for example, Newman and Sproull, 1973) ,
as well as the general computer newspapers and monthly magazines, such as
Personal Computer World, Practical Computing, Interface, etc . It does not
matter if you do not immediately understand the more advanced articles: it is
important to appreciate the flavour, excitement and achievement of the subject.
Obtain the promotional and advertising literature of the major graphics com-
panies (Tektronix, Imlac, A.E.D ., Sigma, Hewlett-Packard, D.E.C., etc.), and
get as much information as possible about graphics software packages. Keep an
eye on the television usage of computer graphics, whether it be in science pro-
grams, science-fiction melodramas or advertisements. Study video games and
try to understand from the display how the characters are drawn and
manipulated .
Index

A 65, 143, 162 backing store 31


ABSOLUTE 69,70,154, ISS, 158 ball 25,60
absolute 8 bar-chart 110
absolute value 46,53 ,126 bars 109, 110, 114
accents 94 base vector 47 ,49,50,53 ,59,125-7,
ACfUAL 69,70,72-6 ,79,80,154-63, 129,137,141,153 ,185
165,182,187 BASIC 1,5 ,7,16 ,23,27,29 ,30,31,36,
acute angle 55 54,62,65,76,113,205,207-209,212,
addressable points 27 214-18,221,228
Adjoint method 64,134 ,148 battle formation 76
aeroplane 167,221,229 BEEP 13,219,235,236
algebra 43 BIN 6, 15,86,88,228
algebraic expression 56 binary 18
ALPHA 69 binary bits 6
alphabetic character 89,166 binary switch (on/off) 5,11
alternative characters 89-102 binary representation 6
amplitude 46 bits 6 ,18
analogue input 103 black 6,12,15-18,106,230
angle 20,53-5,74,146,149,153,159, block graphics 83,85,86
160 blue 16-18,219,221,229
angle between lines 127,128 body of revolution 2,167-9 ,176,189
animation 14,19,71,201,209,233 body of rotation 170, 171
anti-clockwise 41,57,58,68 ,94 ,140, BORDER 6,51,218,219 ,221
172-6 ,190-93,201 bottom left-hand corner 27, 29
arc 20,56 ,116, 117 bottom row 152
areas 27,69,70 bouncing point 19
arrays 32,35,62,69,71,72,79,80, boundary 8, 19
129,130,135,160-62,172,180, boundary polygon 57-9
181,187,196,201 brackets 28,46,125,203
array bound error 76 brain teaser 237
array index see index BREAK 219
assembler 208 BRIGHT 15-18, 105,204,229
assembly language 208 building brick 70, 71
astroid 78 BYTE 2,6
AT 16,204,218
ATN 54 C 161
ATTR 16,23 CalComp 33,48
attribute IS, 16, 18, 105, 230 calculus 43
attribute conversion 16,17 capitals 96
attribute file 15,16,18,209,239 Cartesian 27, 29,31, 124
axes, axis 29,33,49,51,69,110 ,119 , cascade 230-34
124,146, 149 cassette 2, 31, 96, 241, 255
axis of rotation 149-51 ,153,169 castling 101
Celtic 21,38
B 65,143,162 centre 36,42,54,77,106
background 5,6 ,114,228-30,233 CHARS 83-5,89,94,207
Index 247

charact er 7, 83 coordinates 29,32,35 ,37,54,62,236


character block 7,9,15,16,18,19,21-3, coplanar 130
25,33,83 ,84,86,103 ,109,110,119, COpy 87,94
161,205,206,228,229,236 copyright 83
character code 2,85 COS 35,54
character editing 89 cosine 34, 122
character generation 89 Cosine Rule 55
CHARACTER GENERATOR 89-95,99, crosswires 103
102,107,109,119,203 ,228,229,238 crossword puzzle 235
character graphics I, 83 crystallography 236
character set 83,87,89,93,95,107,207 cube 156, 157, 159, 162-6, 172, 174,
character table see table 181,183,186 ,187,193,196,199,200,
chequer board 88 212
chess 99,102,237 cuboctahedron 198,199,201
chesspiece 99 cursor 14,93,103,104,106 ,116,203,
CHR$ 204 204,236
CIRCLE 19,20 ,36 curves 28,37,39 ,40,55,56,106,139,
185 .
circle 19,36,37,41,42,59,60 ,106,117
circumference 36 curved lines 117
cyan 16-19,219
CLEAR 94 ,210,238
clipping 51,82,162,189,238
clock 235 D 180
clockwise 57,140,172-5 ,190-93,201 dashed line 48,49,52
close up 189 DATA 94,163,168,208,238
cloud 221,228,229 data base 72,79 ,80,160,161 , 165
CODE 83,85-7,204,205,207,214,215 , data graph 1,102,103,107
218 data structure 201
coefficients 64, 65 debugging 114
cogs 41 decimal 6,120,214
collisions 23 defmition set 169
colon 218,219 degrees 34, 127
colour 5,6,15,18,21,23,33 delete 93,212,220
colour code 18 DELETE 204
colour sensor 18 determinant 63 ,64,131,136
column 16,62,104,206 diagonal lines 37
column vector 62-5,74,134,137,143, DIM 76,153
144,151,152 dimension 28
combination of transformations 65 ,66 direction 28,53,54,126
command 5-9,11 ,19,93 direction cosine 54,55,126,127, 129
commutative 63 directional vector 47,49,50,53-6,59,
composite colour 18 125-30,132,141 ,151,153 ,185
concentric circles 86 disc 41,42
cone of vision 183,185,189 discrete curve 121
conic section 59 discrete points 12
connected 56 ,138 disphy 5,9,11,12,20,88,207 ,218
construction routine 70,72,75,79,80, display file 6,7,15 ,18,84-6 ,105 ,
161,169,187 205-209,212,228,239
CONTINUE 114 distance 46,53 ,57,124,126 ,129,183,
continuous curve 121 189
control codes 204, 205 dominoes 95
convex 57-9,174-7,185,190-92,201 dot product 127-30,132,151
coordinate axes see axes DOUBLE 94,96
coordinate geometry 27,43, 124 DRAW 7-9,13,19,20,31,39 ,51,52,
coordinate origin see origin 88,89,105,106
coordinate pair 28 drawing board 182
coordinate system 33,45,62,69-71 dual interpretation 48 ,125
coordinate representation 128 DX 69,155
coordinate triple 124,156,163 DY 69,155
248 Index

dynamic scene 82 green 16-18,93 ,94,106,221


DZ 155 grid 8,9,93,94,167,179 ,180
gun 221
E PPC 215
edges of square 14 H 161
EDIT 203,219,220 hatching 115-17
editor 93 head tilt 69,155,160
efficiency 76, 217 hexagon 161
Egham 110, 113 hi-byte 212,213
electron beam 5 hidden lines, surface 1,2,110,114, 139,
ellipse 37,59,60,77,78 140, 154,chap. 10, 190 , chap. 12
ellipsoid 169 high resolution 9,18,19,21,35
en passant 101 highest common factor 42 .
ENTER 102,103,214 highlight 2, 205
envelope 40 histogram 1,102,107,109,110,236 ,
Euclid 43 238
Euclidean geometry, space 27,43 HORIZ 29
Euclid's algorithm 42 horizon 182
EX 155 horizontal lines 8, 9
extended keys 204 horizontal rows 27
EY 155 horizontal set 169
eye 69,82,155-60,184,187 hyperbola 40,59
EZ 155

F 161 icosahedron 198,199,201


facet 154,155,161,172-5,183 ,185, identifier 1
190-96,201 identity matrix 63,65,71,73,75,150,
fanfare 22 157
file handling 204 IF 23
flag 235 illuminated dots 18
IN 1,2
FLASH 15-19,105
index 35,79
FN 2,218
information 62,79
FOR loop 6,8,10,95,153
INK 5-8 ,11,15,16 ,18,19,21,33 ,88,
foreground 6,228
94,95,103,105,106,109,205 ,229,
format 120 230,233
fourth dimension 236 ink blot 95
fractal 9 INKEY$ 8
frame 27, 29, 209 input parameter 1,39
French 94 INPUT 8,9,12,43,71 ,82,84,85,99,
functional representation 55 ,56,59,60, 116,121,203,204
121,137-9,192 inside polygon 57, 58
INT 29
game 14,22,23,25,95,218,237 integer pair 7
gameset 228 intersection 45 ,49,50,51,59 ,60,116,
garbage 161 117,128-31 ,134,136,137,141,183,
general form 37 201
generalpoint 45,46,53 ,125-7,133, INVERSE 11,14 ,15
138,185,192 inverse matrix 64,68,134,136,148,149
geometrical art 34 inverse transformation 68, 148
GO SUB 1,93,215,218 invertebrates 118
GO TO 215,218,219 ISLAND DEFENCE 221-34 ,240
graph paper 167
graphics characters 85-9,93
graphics frame, area, rectangle 27-9 ,35, jaggedness 35
51,52,75,104,180,189,228 jet 166,167
graphics mode 83,85 ,88,89,93 joystick 103
graphics package 1, 27, 33
graphics pen 8,19 Kells 39
graphs 1,107,109,118-20,236,238 key 8,93,203,210
Index 249

keyboard, control 5,9,13,14,22,25,76, microfilm 35


83,87,103,204,232 mid-point 192
minicomputer 5
L 70,79,161 minor axis 37,60,77
labels 107,109,110,126 missile 221,233
lattice 103 mnemonic 208
LDIR 208 modular programming 1, 22, 71, 107,
left-biased 119 164,176
left-hand corner (bottom) 6, 93 modules 1
left-hand corner (top) 27,29,230 modulo 41 ,46,57,58,140
left-handed triad 124, 146 modulus 126,127
length 126 Moire patterns 236
LET 1, 209, 217 monitor 18
libl 2,31 MorseCode 235
lib2 82 movie 82,210,212
lib3 3, 171 music 236
library me 31 mutually perpendicular 33,56,151
limitations 166,191,196
line of sight 155, 160 negative sense 125, 126
linearly dependent 125 negative set 56, 138, 139
linear equations 143 NEXT see FOR
linear transformation 62,64,66, 143 NOF 161
lines 8,11-13,27 ,28,30,35,49,50,69, NOL 79,161
70, 76, 105, 129, 130, 139, 141, 154, non-eollinear 132, 133, 139
155,156,161,167,174,176,181,184, non-eommutative 132
186, 196 non-singular 64
linked list 201 normal 37,128,129,133,135,136,141,
LIST 9,105 ,220 155,185,186
LOAD 2,94, 103, 106,209,210,218, NOV 79,161
221,228,238,241 number theory 43
lo-byte 212,213 NUMH 169
logical expression 23 NUMV 169
logo 235 NXPIX 27,29,35
long shot 189 NYPIX 27,29,35
look-up table 212
low resolution 9, 19,21,25,35 object 69-71, 154
lower case 1, 3, 22, 96 OBSERVED 69,70,72,75,78-80,155-63,
165,172,187,191
machine-code 207~9 , 212, 218, 221, 234 observer 70,82, 182
magenta 16-18 obtuse angle 55
main-frame computer 5 octahedron 174, 199,201
maintain the vertical 159 OFF 93
major axis 37,60,77 optical illusion 37, 38
mapping 29, 189 orange 88
MASTER MIND 95-9,102,204 orientation 57,58,68,76,82,94, 140,
masterset 96 141,172-6,191-3
matrix chap. 4, chaps. 8-12 origin 27-33,35-8,41,46-8,53-5,66-9,
matrix addition, sum 62 ,63, 143 71,73,74,76,124,129,139,140,146,
matrix multiplication, product 63-5, 149,155,184-7,201
143, 144, 152 orthographic chap. 9, 187
matrix of coefficients 65 OUT 1,2
matrix of pixels 27,28 OUTput parameter 1
matrix representation 62,65, 143 outside polygon 57,58
matrix transformable 78 OVER 11-13,103,109,113,114,233,
maze 236 236
medium resolution 86,237
memory-mapped 6 P 69,154
menu 203, 204 PAC MAN 221,237
MERGE 2,31 ,94,95,110,212,238,241 pad 106
250 Index

page 205,206 prompt 203


PAPER 5,6,11, IS, 16,18, 19,25 ,88, pyramid 166,174,189,199
95,103, lOS, 114,204,205,229,230 pyramid of vision 189
parabola 59 Pythagoras 46 ,55
parallel 28,29,38,47,49-51,126,129,
130, 132, 136, 141, 155 Q 69,155
parameter 37,41 quadrants 53
parametric forms 55,56,59,60,78, 125 quadratic equation 60
passing arrays 69 quadrilateral 175, 176
patterns 11, 12,21,25,34,37 ,42,43,46, quarter blocks 86
88,95,236 quarter-circle 39
PAUSE 218,219,231 quote marks 93
pencil 41,42
PEEK 207,213 R 65,70, 143, 159, 161, 162
perpendicular projection 56, 124 radians 20,34 ,36,54,72,73 ,82, 116
perspective ISS, chap. 11 radius 19,36,37,78,116,139
perspective plane 183, 184, 189 rainfall 110
pH 122 RAM 85, 88, 89
PHI 169 random 13, 16, 236
PI 20,34 rapid transfer 207
pie-charts 1, 102, 103, 107, 109, 115-17, raster scan 5
236,238 ray 183
ping-pong 25 READ 8, 94, 122
pixels 7,8 ,10-12,14,18,19,25,27-30, rectangle 31
35,51,52,67,83-8,93,103,105,110 , rectangular block 164, 174,236
180,181,189,228 rectangular matrix 27, 28
pixel coordinates 9 red 16-19,88,104,219,221
pixel vector 27 reflection 67,69,74,78,95,116 ,146
planar object 166, 191 registers 208
plane 27,128,129,132-4,136-42,192, regular polygon 35
201 relative 8, 20
PLOT 7-10,13,31,33,51,52,88,89, REM 1,2,204,205,213,238,241
93, lOS, 106 renumber 93,212,220
plane constant 129,135,141 resolution 35,36
plot pen, head 29, 30, 33, 36, 37 RESTORE 215
point 8, 11-13,28,29,47, 105, 129, 140, retina 183
183, 185 rhombic dodecahedron 199,201
point of contact 42 right-biased 119
point of reference 76 right-handed triad 124
point vector 46,126 RND 13
pointer 201 road sign 235
POKE 6, 16,84,88,207-209,212,228 ROM 83,85 ,94
polygon 9, 14, 27, 28, 32, 34, 57, 59, 76, roots 60
106,140,141,154,161,174,176, ROTATE 94,95,109
183,190,203 rotation 66,68,69, 73, 77, 78, 94, 109,
positions 154 143,146,148-51,153,156,158,159,
positive sense 125, 126 170, 171, 176, 236
positive set 56, 138, 139 rotation matrix 68, 73
postmultiplication 65,153 rounding errors 129
PPD 183 row 16,62, 104,206
prefix 107 row vector 64,65 , 143
premultiplication 64,65,74,143, 144, RUN 2,94,215,220,221
153,158,163
primitives 27, 28, 30, 32 S 169
principal range 54 saw-tooth pattern 121
PRINT 9, 15, 16,21 ,83,84,94, 113, SAVE 2,94,95,106,209,218,238,241
204,213,217 ,218,228,229,233 scalar 45,63
program variables 1 scalar multiple 45,46,53 ,63, 124-6,130,
projection 154 143
Index 251

scalar product 55,127 T 169


scale 28,29,33 , 110, 119, 236 table (of characters) 83, 87,89, 207
scaling 66-9,73 ,143,145,146 ,148,151 table and chairs 82
scaling factor 29,33 tangent 45
scaling matrix 67 tangential 40
Scandinavian 94 target 22
scene 69,79,161,183 television 18, 189
scientific graphs see graphs temperature 113
screen 5-8,11,13,18,25,27,35,42,51 , template 120
62,69,73,76,83,84,88 ,155-7,180, tennis 221
184,189,206,207,210,221,228 tent 221
screen centre 51 tetrahedron 166, 174, 186, 189, 199,200
screen coordinate system 71 THETA 68
SCREEN$ 23, 238 thin characters 107, 119, 120
scroll 212 three-dimensional clipping 238
segment 8,40 ,41,45 ,51,116 ,140 169 three-dimensional space chaps . 7-12
180, 193 ' , tilt of head see head tilt
top down 1
semicircle 39, 169, 170
sense 48,53,125 ,132 trail 13
transformation 64-6,70,74,76,94, 158
SETUP 69,70,72,73,75,76,78-80 transformation matrix 69, 144, 152
154-63 '
translation 66,68,69,73,76,77 , 143,
shading 201
145,148,151 ,156,158,236
shift 93
transpose 65, 143
side effect 36, 38
trigonometric function 34, 54
similar triangles 183
triskele 21,39
SIN 35,54,122 triangle 140, 142, 173, 175, 176, 181,201
sine 34, 153 two-colour pictures 86, 114, 161, 172,229
sine curve 59
two-dimensional space chaps . 2-4
single-valued function 177
two-dimensional vector 28
singular 64
two -fold symmetry 166
skeleton 156
TX 66,145
slice 116, 176
TY 66,145
space 83,93
TZ 145
space ship 72-6 ,78, 80,82
special characters 109 UDG 87,88
SPECTRUM 2,5,9,18,19,27,34,35 , unit distance 28
83,93-5 , 110, 196
sphere 139 unit matrix 63
unit vector 53-5, 126, 127
spheroid 169, 210
spiral 37-9,59 user-defined 83,87-9,93,96,109, 110,
Spirograph 41 ,42 239
square 9,10,14,31,32,41,46,47,156 user friendly 203
squash game 25 USR 87,88,209
standard set 83
star-shaped 199-201,212 V 80,161,165,187
STOP 114 vanishing point 185, 186
storing information 79 variable entry point 230
straight-ahead ray 183 vecto r 27,28,45-50,53,62,124,125,
straight line 35,45,56,125,166 132-5,141, 142
STR$ 204 vector addition 45,46, 124
sUbro~tines 1,22,25,33,161,162,218 vector combination 47
subscript 57,58,62,71,73 vector pair 47
superscript 62 vector product 132,137,141
surface 137-9,174,177,179-81 ,190 vector sum 125
SX 67,145 VERT 29
SY 67,145 vertex, vertices 32,35,62,69-76,140,
symmetry 95 154-6,160,161 ,167,172-4,184,186,
system variable 83 201
SZ 145 vertical column 27
252 Index

vertical labels 109 x-direction 42, 75


vertical line 8, 9 XMOVE 30
vertical set 169, 176 XORIG 29
video game 25,203 ,221 XPEN 29
view 80, 82, 164-7, 180 XYSCALE 29,33 ,36
view plane 155,157,159,180, 182, 183,
189-92 Y 70,79,160
vision 183 y-a.xis 27,28,33 ,45,54,67,94,95 ,124,
volumes 27 147, 149, 156, 158, 159, 169
y-coordinate 28,30,32,45,46 ,51 ,59,
W 80,161,165,187 67,121 ,124 ,145,154 ,160,177,183
well-behaved curves 59 yellow 16-18,88,93 ,219,221
white 6,15-18,94,221,229,230 YMOVE 30
window 29 YORIG 29
wire diagram 156, 172, 174, 212 YPEN 29
worm 22,204
Z 160
X 70,79,160 z-axis 124,147,149,155-60,173
x-axis 27,28,33,37,42,45,53,54 ,74, z-coordinate 124,140,154 ,155,160,
94,95,121,124,146,147,159 177,179,183 ,189
x-coordinate 28,30,32,45,46 ,51 ,59, zero set 56, 138
67,121,124,145,154,160,177 ,179, zoom 14,82, 162
183 ZX Spectrum 5,87,205 ,207
Where to Find Routines referred to in Text

ammo 225 hidden 194


angle 54 hiscore 227
bar 111,113 histo/type1 111
big pixels 86 histo/type2 113
bomb camp 226 icosahedron 198
bomb gun 226
camp 223 idR2 66,77
celtic 38 idR3 144
char 227 in 118
CHARACTER GENERATOR 89 ink 105
charset 101 input 100, 204
CHESS GAME 99 intersection (line and plane) 130
circle1 36 intersection (three planes) 135
circle2 36 intersection (two lines) 131
clip 53 intersection (two planes) 138
construct tables 213 inv 135
create 109,227 ISLAND DEFENCE 222
credit 227 jet 168
cross 232 key 24
cross cascade 232 keyboard 223
cube 165,175,197 label 107
cuboctahedron 198 line 105
cursor 104 lineto 31, 53
dashed lines 48 list 101,204
delete 216 load 106,210 , 222, 227
DIAGRAM PROGRAM 108 loader 209
dot 231 look2 70
dot cascade 232 look3 160
dotprod 133 main program (2-0) 71
drawit 80,81,166 ,168,188 main program (3-D) 162
drawlin 179 main program (chess) 100
ellipse 78 main program (diagrams) 108
envelope 40 MASTERMIND 96
explode 226 menu 205
Euclid 43 missileroutines 225, 226
f 179 move 100
fanfare 24 moveto 31
flash 100 movie 210
FN A 206 mu1t2 66,76
FN T 207 mult3 144
FNX 30 number 120
FN Y 30 orientation 141, 173
genrot 150 paper 105
gobble 25 pie-chart 115
graph 119 piece 100
grid 104 plane 223
hatch 117 plot 34
254 Index ofRoutines

point 105 slide 210


polygon 33 spiral1 38
print routine 207 spiro 43
query 108 square (outside square) 47
reload 224 star1 199
renumber 216 star2 200
revbod 170, 177 start 29
rot2 68,77 start/restart 222
status 25, 223
rot3 148 surface 178
scale2 67, 77 symbol 120
scale3 145 target 25
scene2 73,75,78,81 thin 109
scene3 3,164,165,168,178,188,197,199 tran2 67,77
scroll (wrap around) 213,214 tran3 145
self-listingprogram 215 vecprod 133
set 222 worm 25
setorigin 30 WORM GAME 23
ship 73,80
Software Cassette

The BASIC program listings described in full in Appendix B


are available on a software cassette, priced at £9.00 (including
VAT) in the United Kingdom .
The cassette is obtainable through major bookshops, but in case of
difficulty it can be ordered direct from
Globe Book Services
Canada Road
Byfleet
Surrey KT14 7JL

ISBN 0 333 35051 0

You might also like