Sie sind auf Seite 1von 287

Computer

Ian Ferguson
Graphics via Java
Ab-libris Ab-libris
the e-book people the e-book people
British Library Cataloguing in Publication Data
Ferguson, Robert Ian
Computer Graphics via Java
(Ab-libris computing classics series)
1. Computer Graphics
I. Title II. Ferguson, Robert Ian, 1966-
ISBN: 1-903561-08-6
Typeset in Durham by Ab-Libris Ltd.
Copyright notice
Copyright 2002 by Ab-libris Ltd.
All rights reserved. No part of this publication may be reproduced, stored
in a retrieval system, or transmitted, in any form or by any means, electronic,
mechanical, photocopying, recording or otherwise, without the prior written
permission of Ab-Libris Ltd., PO Box 287, Durham, DH1 5YZ, UK
Dedication
To Jackie and Andrew
Our little systems have their day;
They have their day and cease to be;
They are but broken lights of Thee,
And Thou, O Lord, art more than they.
From: In Memoriam A.H.H. - OBIIT MDCCCXXXIII.
By Alfred, Lord Tennyson
Foreword
This book is based upon an undergraduate class on Computer Graphics
(52.359) taught at the University of Strathclyde. The author would like to
thank past students for their comments on the material, without which, this
book would never have taken shape.
At first sight, a book on CG with Java is a bit of an odd beast; Java after
all is not renowned for its speed of execution and if there is one application
area which demands high speeds, it is CG and games. Given that the majority
of Computer Science courses are now taught using Java, it does however
make sense from a pedagogical point of view to continue using a familiar
language when studying an unfamiliar application area.
Much material, including demonstration animated applets, further exam-
ples and answers to (some) of the exercises in the book can be found on the
website dedicated to the 52.359 class. The page can be found at:
http://www.cs.strath.ac.uk/~if/classes/52.359
I hope you derive as much fun from the material contained in the book as
I did when I first encountered CG.
Ian Ferguson
Jan. 2002
Contents
Chapter 1 What is Computer Graphics? 12
1.1 Introduction 12
Chapter 2 Concepts, Terms and Definitions 24
2.1 Introduction 24
2.2 Low level concepts 25
2.2.1 Memory Mapping 26
2.2.2 Resolution 28
2.2.3 Screen size 28
2.2.4 Coordinates 29
2.2.5 The origin 30
2.2.6 Colour 30
2.2.7 Image files 32
2.3 2D Drawing 33
2.3.1 Points 33
2.3.2 Lines 35
2.3.3 Shapes 35
Chapter 3 A first graphics program 38
3.1 Introduction 38
3.2 The features of a simple graphics program 40
3.3 Organising your work for Java 43
3.4 Graphics Primitives 44
Chapter 4 Graphics Primitives 53
4.1 Introduction 53
4.2 Drawing straight lines 53
4.2.1 Brute force 54
4.2.2 Bresenhams algorithm 58
4.2.3 An implementation of the line drawing algorithms 60
4.3 Circles 62
4.3.1 Brute force 63
4.3.2 Cheating with 8 arcs 63
4.3.3 Digital Differential Analysis - An incremental algorithm 65
4.3.4 Bresenhams algorithm for circles 67
4.3.5 An implementation of the circle drawing algorithms 69
Chapter 5 Data Structures and Drawing 75
5.1 Introduction 75
5.2 The basic 2d data structure 75
5.2.1 Point2d class 76
5.2.2 Line2d Class 77
5.2.3 Shape2d class 81
5.2.4 Drawing2d class 82
5.3 Adding methods 85
5.3.1 Point2d class 85
5.3.2 Line2d Class 86
5.3.3 Shape2d class 87
5.3.4 Drawing2d class 88
5.3.5 Adding these classes to the simple drawing application 89
5.4 The completed system 91
5.5 The Dry Run 92
5.6 Further methods 92
5.6.1 Drawing vs erasing 92
Chapter 6 2d Transformations 95
6.1 Introduction 95
6.2 Transformations the simple way 95
6.2.1 What is a transformation? 95
6.2.2 Translation 96
6.2.3 Rotation - (about the origin) 98
6.2.4 Scaling 101
6.2.5 Identity transformations 103
6.2.6 Order of transformations 104
6.2.7 Rotation around local origin 105
6.2.8 Other transformations - general cases/ special cases. 108
Chapter 7 Transformations as matrices 111
7.1 Introduction 111
7.2 The Transformations 111
7.2.1 Rotation 111
7.2.2 Scaling 112
7.2.3 Translation 112
7.2.4 Homogenous coordinates 112
7.2.5 Homogenous rotation 113
7.2.6 Homogenous scaling 113
7.2.7 Homogenous translation 113
7.3 Implementing Matrices 113
7.4 Using the matrix class 116
7.4.1 Simple transformation using a matrix 118
7.4.2 Combination of transformations using matrices 118
Chapter 8 Simple Animation and Interaction 122
8.1 Introduction 122
8.2 Changing the drawing in response to user interaction 123
8.2.1 Drawing/erasing 123
8.2.2 Getting keystrokes/mouse-events 124
8.2.3 Double Buffering 125
8.2.4 The hopping frog example 126
8.3 Continuous animation 127
8.4 Animation changes in response to user interaction 130
Chapter 9 Curves 134
9.1 Introduction 134
9.2 Parametric Equations 136
9.3 Splines 137
9.3.1 Representing Spline curves 138
9.3.2 Implementing Splines 141
9.3.3 Disadvantages of splines 143
9.4 Bezier Curves 143
9.4.1 Representing Bezier curves 144
9.4.2 Implementing Bezier curves 146
9.5 Other Curves 150
9.6 The co-existence of multiple kinds of line 150
Chapter 10 3D graphics 154
10.1 Introduction 154
10.2 The 3D coordinate system 154
10.3 Implementing 3d - the basic 3d class structure 155
10.3.1 Points 155
10.3.2 3d Transformations 156
10.4 Projections - Viewing 3d on a flat screen 161
10.4.1 Projection - some definitions 162
10.4.2 Parallel projection. 163
10.4.3 Perspective projection 164
10.4.4 Oblique Parallel projections 165
10.4.5 Isometric Projection 169
10.5 Viewpoint Transformation 170
10.6 Implementing 3d - the data model 173
10.6.1 The Matrix Class 175
10.6.2 Point3d 175
10.6.3 Gitem3d 176
10.6.4 Line3d 176
10.6.5 Bezier3d 176
10.6.6 Transformation3d 177
10.7 Implementing 3d - Drawing, Projections and Viewpoints 179
10.7.1 Setting up the drawing transformation 180
10.7.2 Concatenating the transformations 180
10.7.3 Sharing the drawing transformation 181
10.7.4 Using the drawing transformation 181
10.7.5 Changing the drawing transformation 184
Chapter 11 Improving visual realism 189
11.1 Introduction 189
11.2 Hidden line removal 190
11.2.1 Determining visibility 193
11.2.2 Calculating the normal vector of a surface 195
11.2.3 An alternative approach 198
11.3 Implementing hidden line removal 198
11.4 More complex shapes 203
11.4.1 The Painters algorithm 203
Chapter 12 Rendering, Shading and Colour 210
12.1 Introduction 210
12.2 Illumination 211
12.2.1 Simplifying assumptions 212
12.2.2 Components of illumination 213
12.2.3 Diffuse illumination 214
12.2.4 Diffuse scattering from a point source 215
12.2.5 Specular reflection 216
12.2.6 Combining the illumination 218
12.2.7 Calculating E 219
12.2.8 Implementing illumination 221
12.2.9 Extending to colour 225
12.3 Approximating smooth surfaces with polygon nets. 226
12.4 Gouraud shading 227
12.5 Phong Shading 231
12.5.1 Comparison of Gouraud and Phong 231
Chapter 13 Fine detail - Texture Mapping and Bump Mapping 235
13.1 Introduction 235
13.2 Texture mapping 237
13.2.1 Modulating the colour of the surface 237
13.2.2 Mapping pictures onto surfaces 238
13.3 Tilling 240
13.4 Bump mapping 240
13.5 Some examples of texture and bump mapping 242
Chapter 14 Ray Tracing 245
14.1 Introduction 245
14.2 Follow a ray 246
14.2.1 The Ray Tree 247
14.3 Types of ray 247
14.3.1 Normal Rays 247
14.3.2 Illumination Rays 248
14.3.3 Diffuse Rays 248
14.3.4 Computing the brightness 248
14.3.5 Reducing Computation 248
14.4 Determining Intersections 248
14.4.1 Outline 249
14.4.2 Find the equation representing the light ray 250
14.4.3 Intersection of straight line with a plane 251
14.4.4 Determining where a straight line intersects a plane 251
14.4.5 Determining whether that point is with a given polygon 251
14.4.6 Applying to ray tracing 253
Chapter 15 Fractals 256
15.1 Introduction 256
15.2 Self similarity 256
15.2.1 The Koch Curve 257
15.2.2 The Sierpinski Gasket 259
15.3 The Mandelbrot Set 262
15.4 Utilising fractal geometry 266
15.4.1 Mountains 266
15.4.2 Trees etc. 268
15.5 Fractals and 3D 271
Chapter 16 Closing Remarks 274
What is Computer Graphics? 12
Chapter 1
What is Computer
Graphics?
1.1 Introduction
The field of study known simply as Computer Graphics is vast. It
encompasses just about everything that is seen on a computer screen that
isnt a word or a number and on modern, window-based operating systems,
even they will appear on screen using techniques from graphics.
Table 1 - Diversity in Computer Graphics shows just some of thing
things that could be studied under the heading of computer graphics.
Topic Keywords
Software/
Hardware Examples
Pictures digital drawings, digital
photographs, gifs, bitmaps,
jpegs, drawing tools, multi-
media, digital cameras,
image compression
Adobe Illustrator,
Macromedia Free-
hand
Adobe Pho-
toshop, Paintshop
Pro
Figure 1 - Digital
photographs
Diagrams Line drawings, Computer
Aided Design (CAD), sche-
matics, graphs, business/
presentation graphics
AutoCAD
MS Powerpoint
Figure 2 - Line
drawings and sche-
matics
Table 1. Diversity in Computer Graphics
What is Computer Graphics? 13
The following figures (1-9) show some examples of the various things
that pass as Computer Graphics.
Video .mov. avi, Quicktime, DV
(digital video), video cam-
eras
Adobe Premier Figure 3 - Digital
Video
Graphical User
Interfaces (GUIs)
Windows, icons, menu,
pointers - (WIMPS)
Windows, Xwin-
dows, Mac
Figure 4 - Graphi-
cal User Interfaces
3D Modelling coordinate systems, trans-
formations, clipping wire-
frame drawings, shading,
hidden line removal, pro-
jections, rendering, ray trac-
ing
Autocad AC3D,
POV, Renderman,
Alias Sketch,
Lightwave
Figure 5 - 3D
Modelling - Images
courtesy of
Autodesk(top) and
BBC (bottom)
Virtual Reality Real-time 3D modelling,
interaction, immersive/non-
immersive VR
Virtual Reality
Markup Lan-
guage (VRML).
Figure 6 - Virtual
Reality - (image
courtesy of the Irish
Tourist Board)
Animation Frames, tweening, frame
rates
Macromedia
Director
Figure 7 - Anima-
tion - a frame from
Highnoon - an ani-
mated 3D cartoon
- Image courtesy of
Michael G. Turner)
Image Processing filters, image enhancement,
medical imaging, astron-
omy, maximum entropy
techniques,
Khorus Figure 8 - Image
Processing- a raw
and processed brain
scan
Image Analysis Edge detection, histogram-
ming,
Khorus Figure 9 - Image
Analysis - street
scene and edge-
detection
Image Comprehension image recognition, pattern
recognition, face recogni-
tion, neural networks
(still experimen-
tal)
Graphics Hardware display devices, VDUs,
LCDs, plasma screens,
TFT, goggles, VR head-
sets, Projection systems,
interaction devices (mouse,
bat, light pen, digitising
pad, graphics tablets, panto-
graph)
Topic Keywords
Software/
Hardware Examples
Table 1. Diversity in Computer Graphics
What is Computer Graphics? 14
Figure 1. Digital photographs
What is Computer Graphics? 15
Figure 2. Line drawings and schematics
book
author
library
What is Computer Graphics? 16
Figure 3. Digital Video
What is Computer Graphics? 17
Figure 4. Graphical User Interfaces
What is Computer Graphics? 18
Figure 5. 3D Modelling - Images courtesy of Autodesk
1
(top) and BBC
2

(bottom)
1. www.autodesk.com
2. www.bbc.co.uk
What is Computer Graphics? 19
The same techniques that let architectural clients see a building that hasnt
even been built yet allow the creation of the impossible such as this extinct
creature from the BBC series Walking with Beasts
Figure 6. Virtual Reality - (image courtesy of the Irish Tourist Board
1
)
1. www.ireland.travel.ie
What is Computer Graphics? 20
Figure 7. Animation - a frame from Highnoon - an animated 3D cartoon -
Image courtesy of Michael G. Turner)
Figure 8. Image Processing- a raw and processed brain scan
What is Computer Graphics? 21

Figure 9. Image Analysis - street scene and edge-detection
This book concentrates on the terms and techniques that underlie the top-
ics of diagrams, 3d-modelling, virtual reality and animation.
What is Computer Graphics? 22
Chapter review - 1
Theres not a great deal to summarise so far but you seen examples of the
great variety of topics that make up the study of computer graphics
What is Computer Graphics? 23
Exercises - 1
1.1 Surf the WWW. Find examples of the different type of computer
graphics applications mentioned in Chapter 1
1.2 Look at:
www.cs.strath.ac.uk/~if/classes/52359
www.streetmap.co.uk
www.sat.dundee.ac.uk/
www.wunderground.com/sky/ShowSky.asp?The-
Lat=52.200001&TheLon=0.180000&TimeZoneName=Europe/
London
javaboutique.webdeveloper.com/Mandelbrot/
www.vrml.org
cgw.pennnet.com/home.cfm - the gallery section is particularly
well worth seeing.
www.computer.org/cga/
Concepts, Terms and Definitions 24
Chapter 2
Concepts, Terms and
Definitions
2.1 Introduction
Before examining to different specialisms that make up computer graph-
ics, this chapter provides a quick review of the basic terms and definitions
that are common to most areas of computer graphics.
Concepts, Terms and Definitions 25
2.2 Low level concepts
All of computer graphics is based upon the properties of the screen or dis-
play device (more about this in Chapter ##). The fundamental thing that you
need to know about displays is that they are divided into lots of small squares
called pixels (PICture ELements).
Figure 10. Pixels
Concepts, Terms and Definitions 26
The simplest way to think of how this works is to stick to black and white.
Each pixel can be set to black or white (i.e. turned on or off). This allows pat-
terns of dots to be created on the screen.
Figure 11. Smiley pixels
2.2.1 Memory Mapping
Drawing on the screen is therefore simply a matter of setting the right pix-
els either on or off. Each pixel on the screen corresponds to an address in the
computers memory - this is known as memory mapping and the display is
said to be a memory mapped display. Effectively, each pixel is numbered -
sequentially.
Concepts, Terms and Definitions 27
Figure 12. Memory mapping
By writing values to the correct locations in memory (this used to be
called poking the address) the appearance of the screen can be controlled
by a programmer. Conversely, by inspecting the contents of a memory loca-
tion (peeking), a program can find out if a pixel is turned on or off.
Aside The portion of memory that is associated with the display is known as the
video memory. In the PC architecture, this memory is usually physically
located on the graphics card, which is why you can buy 8Mb graphics cards,
16Mb graphics cards etc.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
260 261 262 263 264 265 266 267 268 269 720 271 272 273 274 275 276 277 278 279
280 281 282 283 284 285 286 297 288 289 290 291 292 293 294 295 296 297 298 299
off 0
off 1
off 2
off 42
off 42
ON 44
ON 45
off 46
off 47
off 48
ON 49
ON 50
off 51
off 296
off 297
off 298
off 299
Screen
Memory
Concepts, Terms and Definitions 28
2.2.2 Resolution
The screen in this example is composed of 300 pixels arranged in 15 rows
of 20. It is said to have a resolution of 20 by 15 (20 x 15). This is actually
very small by todays standards. Typically a display will have a resolution of
1024x768 maybe even more.
2.2.3 Screen size
Resolution is NOT the same thing as screen size. Our 20x15 display could
have been 5cm across (as a mobile phone display), 40cm across (as a moni-
tor) or 20m (as a projection system) but the resolution would always be
20x15.
Figure 13. Screen size is different to resolution
Concepts, Terms and Definitions 29
2.2.4 Coordinates
Whilst the computer thinks of its display as a simple list of addresses, it
is much more convenient (for reasons which will become clear later) for us
to think in terms of coordinates and leave it to the computer to convert the
coordinates to memory location itself.
Figure 14. Coordinates
Each pixel can be referred to by a pair of numbers known as its coordi-
nates - an x coordinate (which gives the columns number and a y coordinate
which gives the row number. The coordinates are always written as a pair of
numbers, separated by a comma and enclosed in brackets. This system of
geometry is known as Cartesian geometry and the coordinates are spoken
of as being Cartesian Coordinates.
Example 1. Simple coordinate example
In Figure 14 - Coordinates - pixel (7,12) is set ON.
Aside The computer converts coordinates to memory addresses by subtracting the y
coordinate from the number of rows on the display minus 1 (i.e. Ysize -1,
this effectively turns the y axis upside-down to make sure that the origin is at
the bottom), multiplying that by the number of columns on the display
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 0
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
X
Y
Xsize = 20 (columns)
Ysize = 15 (rows)
Concepts, Terms and Definitions 30
(Xsize), and adding the x coordinate.
location = (((Ysize - y)* Xsize) + x). (Equation 1)
(7,12) becomes (((14-12)*20) + 7) = 47
2.2.5 The origin
In this example, the origin or (0,0) is in the bottom-left of the screen. It is
also possible to have the origin in the top-left, in which case the rows (y
coordinates) are numbered downwards
2.2.6 Colour
In discussion so far, we have been restricted to black and white (mono-
chrome) i.e. each pixel can only be on or off. Colour can be represented in
most of todays computers. Typically, instead of each pixel being represented
by one bit (on or off) each pixel will be represented by 24 bits - 3 x 8 bit
bytes. Each byte represents a number between 0 and 255 and each byte is
associated with one primary colour - red, blue, green.
Figure 15. 24 bit colour representation
0000 0000
red green blue
0000 0000 1111 1111
0 0 255
00
00 FF
binary
decimal
hex
1100 0000 1100 0000 0000 0000
192 192 0
C0
C0 00
binary
decimal
hex
Concepts, Terms and Definitions 31
Figure 16. Colour smiley
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
260 261 262 263 264 265 266 267 268 269 720 271 272 273 274 275 276 277 278 279
280 281 282 283 284 285 286 297 288 289 290 291 292 293 294 295 296 297 298 299
FF FF FF 0
FF FF FF 1
FF FF FF 2
FF FF FF 42
FF FF FF 42
FF 00 00 44
FF 00 00 45
FF FF FF 46
FF FF FF 47
FF FF FF 48
FF 00 00 49
FF 00 00 50
FF FF FF 51
FF FF FF 296
FF FF FF 297
FF FF FF 298
FF FF FF 299
Screen
Memory
Concepts, Terms and Definitions 32
2.2.7 Image files
From Figure 16 - Colour smiley it is hopefully only a small step to see
how Figure 17 - smiley.bmp works. The pattern of bits in the computers
memory forms what is know as a bitmap.
Figure 17. smiley.bmp
By simply writing those values out to a data file and prepending informa-
tion about the height and depth of the image, a picture can be saved onto disk
and this is indeed the approach taken by all the common graphical formats
seen on the WWW such as.gifs,.jpegs, etc.
44 45 46 47 48 49 50
64 65 66 67 68 69 70
84 85 86 87 88 89 90
104 105 106 107 108 109 110
124 125 126 127 128 129 130
144 145 146 147 148 149 150
164 165 166 167 168 169 170
184 185 186 187 188 189 190
204 205 206 207 208 209 210
7
9
FF 00 00 FF 00 00 FF FF FF FF FF FF FF FF FF FF 00 00 FF 00 00
FF 00 00 FF 00 00 FF FF FF FF FF FF FF FF FF FF 00 00 FF 00 00
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF 00 FF 00 FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF 00 FF 00 FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF 00 00 FF FF FF FF FF FF FF FF FF FF 00 00 00 FF FF FF
FF FF FF FF FF FF 00 00 FF 00 00 FF 00 00 FF FF FF FF FF FF FF
Concepts, Terms and Definitions 33
It is then an even smaller step (increase the number of pixels (i.e the reso-
lution)) to see how Figure 18 - Carol Smiley works.
Figure 18. Carol Smiley
1
2.3 2D Drawing
Leaving image processing behind for now, we can concentrate on the
basic terminology associated with drawing on a computer screen. In two
dimensions (2D), drawing are made up of points, lines and shapes.
2.3.1 Points
Representing a point on a 2d drawing to a computer is simple. In fact
youve already seen it, we just use coordinates.
1. - Image courtesy of the BBC - www.bbc.co.uk
Concepts, Terms and Definitions 34
Figure 19. Using coordinates to represent points
Aside It is worth noting at this stage two important points about the difference
between coordinates that you will have come across in a maths course and
those used by computers:
1. At the lowest level, a computer only understand integers as coor-
dinates. If you want to plot a point at (5.673,48.32795) you will
need some scheme for converting it sensibly into an integer value.
2. In maths, a point has no size, it is infinitesimally small. To a com-
puter, a point is the size of a pixel.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 0
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
X
Y
7
12
Concepts, Terms and Definitions 35
2.3.2 Lines
A (straight) line can be mathematically defined by its end points. To
describe the line in figure X we need simply to state the coordinates of the
two ends: (3,8),(12,2)
Figure 20. Defining a line using the start and end points (3,8),(12,2)
Aside Another difference between raw maths and computer graphics, a line has no
thickness, in computer graphics, it does.
2.3.3 Shapes
At this stage all you need to know is that shapes are made up of collec-
tions of lines.
3
8
2
12
Concepts, Terms and Definitions 36
Chapter review - 2
So far, you should have learned about:
screens being divided into pixels, resolution and size
memory mapping - whereby each pixel has a corresponding
address in video memory which can be set or read to set or interro-
gate the colour of the pixel
the 24 bit colour representation scheme
the concept of bitmaps whereby patterns in memory can repre-
sent the appearance of the screen
a simple image file format
the representation of point and lines by means of cartesian coordi-
nates
Concepts, Terms and Definitions 37
Exercises - 2
2.1 Find out the size, resolution and colour depth of the display you
are using.
2.2 Describe the difference between size and resolution
2.3 What steps must a computer take to plot a point (22.25,10.4)?
A first graphics program 38
Chapter 3
A first graphics program
3.1 Introduction
It is traditional, when learning to program, that you start with a Hello
World program. In this chapter, we will look at the graphics equivalent of
that textual tradition. The code for this is below in example 2.
Example 2. Apollo 13
1 //------------------------------------------------
2 //
3 //
4 // File : Gapp.java
5 //
6 //
7 //------------------------------------------------
8 import java.awt.*;
9 import java.awt.event.*;
10 import javax.swing.*;
11
12
13 public class Gapp extends JFrame {
14
15
16 public Gapp(){
17 setBackground(Color.white);
18 }// constructor
19
20
21 public void initComponents() throws Exception {
22 setLocation(new java.awt.Point(0, 30));
A first graphics program 39
23 setSize(new java.awt.Dimension(350, 400));
24 setTitle("Graphics Application");
25 getContentPane().add(new Gcanvas());
26
27 addWindowListener(new java.awt.event.WindowAdapter() {
28 public void windowClosing(java.awt.event.WindowEvent e) {
29 thisWindowClosing(e);
30 }
31 });
32 }//end - initComponents
33
34
35
36
37 void thisWindowClosing(java.awt.event.WindowEvent e){
38 // Close the window when the close box is clicked
39 setVisible(false);
40 dispose();
41 System.exit(0);
42 }//end - thisWindowClosing
43
44
45
46 static public void main(String[] args) {
47 // Main entry point
48 try {
49 Gapp myGapp = new Gapp();
50 myGapp.initComponents();
51 myGapp.setVisible(true);
52 }
53 catch (Exception e) {
54 e.printStackTrace();
55 }
56 }//end main
57
58 }//end of class -- Gapp -------------------------------------------
1 import java.awt.*;
2 import javax.swing.*;
3 //---------------------------------------------------------------
4 //
5 //
6 // File : Gcanvas.java
7 //
8 //
9 //----------------------------------------------------------------
10 class Gcanvas extends JPanel {
11
12 public void paintComponent(Graphics g){
13 g.drawLine(50,50,50,150);
14 g.drawLine(50,150,100,100);
A first graphics program 40
15 g.drawLine(100,100,100,150);
16 g.drawLine(100,150,200,150);
17 g.drawLine(200,150,200,50);
18 g.drawLine(200,50,100,50);
19 g.drawLine(100,50,100,100);
20 g.drawLine(100,100,50,50);
21 g.drawLine(200,50,250,100);
22 g.drawLine(250,100,200,150);
23 }//paintComponent
24
25 }//end of -- Gcanvas --------------------------------------------
Running this program should result in the output found in Figure 21
Figure 21. Apollo 13 in flight
3.2 The features of a simple graphics program
You cant have it both ways with a programming language, it can either be
simple or powerful. Java most definitely falls in the powerful (consequently
complex) category. In order to draw things on screen (which is what this is
all about) you have to have quite a bit of Java machinery in place before
you can start. Lets look at this machinery first via the simplest Java graphics
A first graphics program 41
program I could write. This program (lets call it Apollo13) consists of two
Java classes - Gapp (graphics application) and Gcanvas. Figure 22 shows a
UML diagram of the program.
Figure 22. Design diagram for a simple graphics application
Gapp and Gcanvas are ours - were developing them. JFrame and JPanel
from which they inherit, are part of the Java Foundation Classes - in particu-
lar they are part of the swing GUI components.
JFrame
Gapp Gcanvas
JPanel
JDK - swing
ours
application
initComponents
thisWindowclosing
paintComponent
A first graphics program 42
The class Gapp inherits from JFrame, so when a Gapp object is created, a
new GUI window appears on the screen. A Gcanvas/JPanel is simply
something we can draw on, but it isnt allowed to be on screen by itself, it
must be part of a JFrame. So what we actually need is an instance of Gapp
with an instance of Gcanvas inside it (Figure 23).
Figure 23. Gapp with a Gcanvas in it
The main entry point for the system is in class Gapp (line 46) - the main
function, simply creates a Gapp object (line 49), and calls its initCompo-
nents() method(50). initComponents() sets the windows on-screen posi-
tion and size (lines 22,23), sets up some Java apparatus to allow the program
to shut down cleanly (lines 27-31) and creates an instance of a Gcanvas
(graphics canvas) - line 25. This GCanvas object is added to the Gapp
object and hence becomes part of that window.
The actual interesting bit of this program occurs in method paintCompo-
nent() in file Gcanvas.java (lines 12-23). Here we finally see how to draw
lines in Java. When paintComponent() is called, it is passed a Graphics
object (g) - line 12. We use a method called drawLine() which is a mem-
ber of the Graphics class. The Graphics class is part of the standard Java
class library and its member functions are termed graphics primitives.
There exist a whole range of methods for drawing and colouring in a variety
of shapes (boxes, polygons, ovals etc.) Take a look at the Java API documen-
tation for full details.
The drawLine() method takes 4 parameters, x1, y1, x2, y2 which repre-
sent the start and end points of the line you wish to draw.
But......?
you may be asking, this program doesnt actually seem to call the paint-
Component() method and where does it get g the Graphics object from?
You are right, it doesnt. paintComponent() is what is known as a call-
back method. Its actually called by the system every time the JPanel
object it belongs to needs to be displayed on screen and likewise the system
passes us the mysterious g to provide all of those useful functions - we
dont have to worry about it.
application
A first graphics program 43
So how is Apollo 13 actually drawn? The drawing is simply broken down
into a series of lines. Each line has a start point and an end point. These
points are expressed in terms of there coordinates and by cross referencing
between Figure 24 and lines 13-22 of Gcanvas.java you can see how the
drawing is built up.
Figure 24. The Coordinates of Apollo 13
3.3 Organising your work for Java
Here are some hints and tips more minimising hassle while trying to get
the examples and exercises working.
Make a directory somewhere called graphics
Do each example/exercise in a separate sub-directory of graphics.
make sure you have . on your classpath
UNIX
- setenv JAVA_HOME /usr/local/jdk1.3/bin
- setenv CLASSPATH "$JAVA_HOME":.
WIN
- set JAVA_HOME=C:\jdk1.3\bin
- set CLASSPATH=%JAVA_HOME%;.
0
50
100
150 200 250 50 100
150
x
y
(50,150)
(100,100)
(100,150)
(50,50) (100,50) (200,50)
(200,150)
(250,100)
A first graphics program 44
3.4 Graphics Primitives
A graphics primitive can be loosely defined as a drawing function which
the system makes available to the applications programmer. An obvious
example is the Java drawLine() method. The subject of what to include
within a system as a primitive can get quite complex because consideration
needs to be given to the properties of the display device. Display devices
include computer screens, printers, plotters and 'barco' type scanned optical
displays. Even within a display device type there may be several alternative
forms (e.g. a 'computer screen may be a CRT vector system, a CRT raster
system or a LCD. A printer may be dot matrix, ink jet, laser etc.). At the low-
est level each device needs its own set of primitives (hardware primitives).
For a raster type display at the lowest level we only need to implement a
pixel(x,y) on - off function. We normally expect to work at a higher level
with a more comprehensive set of primitives which could, for example,
include:
Line, Circle (ellipse?), box, polyline, arc, fill etc.
Java implements a comprehensive set of graphics primitives:
abstract void clearRect(int x, int y,
int width, int height)
Clears the specified rec-
tangle by filling it with the
background color of the cur-
rent drawing surface.
abstract void clipRect(int x, int y,
int width, int height)
Intersects the current clip
with the specified rectangle.
abstract void copyArea(int x, int y,
int width, int height, int dx, int dy)
Copies an area of the
component by a distance speci-
fied by dx and dy.
abstract Graphics create() Creates a new Graphics
object that is a copy of this
Graphics object.
Graphics create(int x, int y, int
width, int height)
Creates a new Graphics
object based on this Graphics
object, but with a new transla-
tion and clip area.
abstract void dispose() Disposes of this graphics
context and releases any sys-
tem resources that it is using.
void draw3DRect(int x, int y, int
width, int height, boolean raised)
Draws a 3-D highlighted
outline of the specified rectan-
gle.
Table 2. The methods of the Graphics class - taken from the on-line Java
JDK manuals
A first graphics program 45
abstract void drawArc(int x, int y,
int width, int height, int startAngle,
int arcAngle)
Draws the outline of a
circular or elliptical arc cover-
ing the specified rectangle.
void drawBytes(byte[] data, int off-
set, int length, int x, int y)
Draws the text given by
the specified byte array, using
this graphics context's current
font and color.
void drawChars(char[] data, int off-
set, int length, int x, int y)
Draws the text given by
the specified character array,
using this graphics context's
current font and color.
abstract boolean drawImage(Image img,
int x, int y, Color bgcolor, ImageOb-
server observer)
Draws as much of the
specified image as is currently
available.
abstract boolean drawImage(Image img,
int x, int y, ImageObserver observer)
Draws as much of the
specified image as is currently
available.
abstract boolean drawImage(Image img,
int x, int y, int width, int height,
Color bgcolor, ImageObserver observer)
Draws as much of the
specified image as has already
been scaled to fit inside the
specified rectangle.
abstract boolean drawImage(Image img,
int x, int y, int width, int height,
ImageObserver observer)
Draws as much of the
specified image as has already
been scaled to fit inside the
specified rectangle.
abstract boolean drawImage(Image img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
Color bgcolor, ImageObserver observer)
Draws as much of the
specified area of the specified
image as is currently available,
scaling it on the fly to fit inside
the specified area of the desti-
nation drawable surface.
abstract boolean drawImage(Image img,
int dx1, int dy1, int dx2, int dy2,
int sx1, int sy1, int sx2, int sy2,
ImageObserver observer)
Draws as much of the
specified area of the specified
image as is currently available,
scaling it on the fly to fit inside
the specified area of the desti-
nation drawable surface.
abstract void drawLine(int x1, int
y1, int x2, int y2)
Draws a line, using the
current color, between the
points (x1, y1) and (x2, y2) in
this graphics context's coordi-
nate system.
abstract void drawOval(int x, int y,
int width, int height)
Draws the outline of an
oval.
abstract void drawPolygon(int[]
xPoints, int[] yPoints, int nPoints)
Draws a closed polygon
defined by arrays of x and y
coordinates.
Table 2. The methods of the Graphics class - taken from the on-line Java
JDK manuals
A first graphics program 46
void drawPolygon(Polygon p) Draws the outline of a
polygon defined by the speci-
fied Polygon object.
abstract void drawPolyline(int[]
xPoints, int[] yPoints, int nPoints)
Draws a sequence of con-
nected lines defined by arrays
of x and y coordinates.
void drawRect(int x, int y, int
width, int height)
Draws the outline of the
specified rectangle.
abstract void drawRoundRect(int x,
int y, int width, int height, int
arcWidth, int arcHeight)
Draws an outlined round-
cornered rectangle using this
graphics context's current
color.
abstract void drawString(Attributed-
CharacterIterator iterator, int x, int
y)
Draws the text given by
the specified iterator, using this
graphics context's current
color.
abstract void drawString(String str,
int x, int y)
Draws the text given by
the specified string, using this
graphics context's current font
and color.
void fill3DRect(int x, int y, int
width, int height, boolean raised)
Paints a 3-D highlighted
rectangle filled with the current
color.
abstract void fillArc(int x, int y,
int width, int height, int startAngle,
int arcAngle)
Fills a circular or ellipti-
cal arc covering the specified
rectangle.
abstract void fillOval(int x, int y,
int width, int height)
Fills an oval bounded by
the specified rectangle with the
current color.
abstract void fillPolygon(int[]
xPoints, int[] yPoints, int nPoints)
Fills a closed polygon
defined by arrays of x and y
coordinates.
void fillPolygon(Polygon p) Fills the polygon defined
by the specified Polygon object
with the graphics context's cur-
rent color.
abstract void fillRect(int x, int y,
int width, int height)
Fills the specified rectan-
gle.
abstract void fillRoundRect(int x,
int y, int width, int height, int
arcWidth, int arcHeight)
Fills the specified
rounded corner rectangle with
the current color.
void finalize() Disposes of this graphics
context once it is no longer ref-
erenced.
Table 2. The methods of the Graphics class - taken from the on-line Java
JDK manuals
A first graphics program 47
abstract Shape getClip() Gets the current clipping
area.
abstract Rectangle getClipBounds() Returns the bounding
rectangle of the current clip-
ping area.
Rectangle getClipBounds(Rectangle r) Returns the bounding
rectangle of the current clip-
ping area.
Rectangle getClipRect() Deprecated. As of JDK
version 1.1, replaced by get-
ClipBounds().
abstract Color getColor() Gets this graphics con-
text's current color.
abstract Font getFont() Gets the current font.
FontMetrics getFontMetrics() Gets the font metrics of
the current font.
abstract FontMetrics getFontMet-
rics(Font f)
Gets the font metrics for
the specified font.
boolean hitClip(int x, int y, int
width, int height)
Returns true if the speci-
fied rectangular area intersects
the bounding rectangle of the
current clipping area.
abstract void setClip(int x, int y,
int width, int height)
Sets the current clip to
the rectangle specified by the
given coordinates.
abstract void setClip(Shape clip) Sets the current clipping
area to an arbitrary clip shape.
abstract void setColor(Color c) Sets this graphics con-
text's current color to the speci-
fied color.
abstract void setFont(Font font) Sets this graphics con-
text's font to the specified font.
abstract void setPaintMode() Sets the paint mode of
this graphics context to over-
write the destination with this
graphics context's current
color.
abstract void setXORMode(Color c1) Sets the paint mode of
this graphics context to alter-
nate between this graphics con-
text's current color and the new
specified color.
String toString() Returns a String object
representing this Graphics
object's value.
Table 2. The methods of the Graphics class - taken from the on-line Java
JDK manuals
A first graphics program 48
Use the on-line Java JDK manuals to find details of these functions. The
full documentation of this class can be found at http://java.sun.com/j2se/1.3/
docs/index.html.
To overcome the dependence of primitives on the display device a variety
of standard 'device independent' software graphics primitives have been
defined. The three most important standards you may meet are GKS (Graph-
ics Kernel System), PHIGS (Programmers Hierarchical Interactive Graphics
System) and X-Windows. A comparison of the relative merits of the compet-
ing systems is beyond the scope of this book. For our purposes, device inde-
pendence is provided by the Java runtime system.
In summary, the process of generating a graphics image on the display
device can be represented by the following pipeline: Figure 25 - Program-
mers model of a computer graphics system - version 2 .
Figure 25. Programmers model of a computer graphics system - version 2
Applications programs rarely (if ever) access the video memory directly -
indeed Java has no facilities to do this. All drawing is done via the graphics
primitives. Further stages in this system will be added later. Workstations
which are optimised for graphics applications (e.g. Silicon Graphics) will
often implement a wide range of graphics primitives in hardware thus speed-
ing up the applications.
abstract void translate(int x, int y) Translates the origin of
the graphics context to the
point (x, y) in the current coor-
dinate system.
Table 2. The methods of the Graphics class - taken from the on-line Java
JDK manuals
Display Video memory application
program
Graphics
Primitives
A first graphics program 49
Chapter review - 3
So far, you should have learned about:
the structure of a basic Java graphics program
how to draw lines in Java
what a graphics primitive is
how an application program actually draw something on screen.
A first graphics program 50
Exercises - 3
3.1 Type in the Apollo13 program and make it work.
3.2 Make a copy of the Apollo 13 program in a new directory and
modify it so that the output looks like this (Hint - you only need
to change one function - paintComponent in Gcanvas):.
3.3 Alter the hi program to say hello world
3.4 Square swirl - Write a Java program to draw a square and then to
draw a second square within the first reduced in size by the
A first graphics program 51
parameter u (see Figure 26 below, try u = 0.1 to start with) and so
on until you have drawn approximately 40 diminishing squares.
Figure 26. The swirling square problem
P Q
R S
(Px,Py)
(Qx,Qy)
(Rx,Ry)
(Sx,Sy)
P1
Q1
R1
S1
(P1x,P1y)
(Q1x,Q1y)
(R1x,R1y)
(S1x,S1y)
P,Q,R,S - are the vertices of the first (outer) square
P1,Q1,R1,S1 - are the vertices of the second (inner) squareu
P1x = ((1 - u) * Px) + (u * Qx)
P1y = ((1 - u) * Py) + (u * Qy)
similarly for Q,R,S
distance PP1
distance PQ
distance SS1
distance SP
= u
0 < u < 1 e.g. u= 0.1
HINT
=
A first graphics program 52
Your answer should look something like Figure 27
Figure 27. Square swirl
3.5 Try the same thing with other shapes, triangle etc. (no answers
for this one - your on your own!)
3.6 Generalise your solution so that it will draw any n-sided regular
polygon.
Graphics Primitives 53
Chapter 4
Graphics Primitives
4.1 Introduction
Having seen the anatomy of a simple Java graphics program, some ques-
tions arise: How does that program relate to the concepts of pixels and mem-
ory mapping that were introduced in Chapter 2? How were the lines drawn?
What exactly did the line:
g.drawLine(50,50,50,150);
do?
In this chapter we will lift the bonnet and see how drawLine(),
drawOval() etc. (the Java graphics primitives) operate. You will rarely need
to program at this level (routines such as these are provided so you dont
have to), but an appreciation of how Java manages to efficiently perform
such operations will influence our later program design.
4.2 Drawing straight lines
Lets start with drawLine(). Were going to develop our own version of
this method and as with so many things in computing there are two ways of
doing it: the brute force approach and the elegant way. Well tackle the brute
force way first to introduce some ideas and then looks at how it can be
refined to produce an efficient (i.e. quick) solution known as Bresenhams
algorithm.
Graphics Primitives 54
4.2.1 Brute force
The starting point (pun intended) is the equation of a straight line:
y=mx+c (Equation 2)
where m is the gradient of the line:
and c is its intercept of the y-axis
(Equation 3)
Assume that the endpoints of the line are known:
Figure 28. Specifying straight lines
m
y
x
------
y
to
y
from

x
to
x
from

------------------------ = =
c y
from
m x
from
( ) =
(x
to
,y
to
)
(x
from
,y
from
)
y
x
c
Graphics Primitives 55
For any value of x we can compute y. Fortunately, in the quantized, inte-
ger valued world of computer graphics and bitmapped displays we know all
the values of x. Figure 29 shows a rather course-grained bit mapped display
superimposed upon the mathematical straight line of the previous diagram.
Figure 29. Enumerating the values of x
A for loop can be used to iterate through all the values of x between x
from
and x
to
and for each of these, the corresponding y value calculated.
for(int x= xfrom; x<xto; x++) {.......}
In order to use Equation 2, we must have values for m and c. Since we
know two points on the line, these can easily be computed.
Thus, the routine (in pseudocode) to draw a line might look like this:
method lineDraw(xfrom,yfrom,xto,yto){
DeltaY = yto-yfrom;
DeltaX = xto-xfrom;
m = DeltaY/DeltaX;
c=yfrom - (m*xfrom);
for(int x= xfrom; x<xto; x++) {
y=(m*x) + c;
plotPoint(x,y)
}
}//lineDraw
x
from
, x
from+1
, x
from+2
.....x
to
Graphics Primitives 56
The results of running such an algorithm look like Figure 29. Unfortu-
nately, if we pick coordinates for the end points such that the line is steep (in
fact when its gradient m is >1 the results look something like Figure 30:
Figure 30. Brute force algorithm with steep gradient
Gaps start to appear in the line. Why has this happened? Looking at some
values for x and y soon reveals that when m>1, the values for y increase by
an amount greater than the increments of x that we are using (i.e. >1). Com-
pare the lines
x
from
= 10, y
from
= 10, x
to
= 40, y
to
= 30 (Figure 29)
x
from
= 10, y
from
= 10, x
to
= 40, y
to
= 90 (Figure 30)
The solution to the gaps problem is to always use the most rapidly chang-
ing variable (x or y) as the index to the loop (Figure 31). i.e.When the gradi-
ent (m) >1 - use y as the control variable in the loop and make x the subject
of the equation:
x = (y-c)/m (Equation 4)
Figure 29 Figure 30
x y x y
10 10 10 10
11 11 11 13
12 11 12 15
13 12 13 18
14 13 14 21
Table 3. Comparison of x & y values for different gradients
Graphics Primitives 57
Figure 31. Control variable usage depend on line gradient
There is a second problem with the brute force approach: It requires float-
ing point arithmetic which is slow when compared with using integer only
arithmetic. An approach which used solely integers would result in a much
quicker algorithm.
m = 1
m = -1
use x
use y
use y
use x
Graphics Primitives 58
4.2.2 Bresenhams algorithm
One such integer only algorithm is Bresenhams. Start by considering the
simple case where 0 < m <1
Figure 32. The basis of Bresenhams algorithm
Consider, as before, iterating the x values from left to right. If the pixel at
(x
i
,y
i
) has been plotted, then the next one MUST be either (x
i
,y
i
) or (x
i
,y
i+1
).
Why? - because of the gradient - it cant go up more than one step in the y
direction for one step in the x (m<1) and it cant go down at all (0<=m). How
can we work out which pixel to plot? - by calculating the difference between
the true mathematical value of y at x
i+1
(well call that y
real
) and the y values
represented by the pixels. y
1
andy
0
present these distances and the decision
on which pixel to plot can be made by following the following pseudocode
if y
0
> y
1
then
plot pixel at y
i+1
else
plot pixel at

y
i
How then are y
1
andy
0
calculated?
y
1
= (y
i
+1) - y
real
= (y
i
+1) - m(x
i
+1) -c
x
i
x
i+1
y
i
y
i+1
y
1
y
0
y
real
Graphics Primitives 59
y
0
= y
real
- y
i
= (m(x
i
+1) + c) - y
i
Subtracting the two expressions gives:
y
diff
= y
0
- y
1
= 2m(x
i
+1) + 2c -2y
i
-1 (Equation 5)
if y
diff
> 0 then
plot pixel at y
i+1
else
plot pixel at

y
i
At this point, were still using m which is a real number, but
m = y/x
substituting this into Equation 5 gives:
D
i
= x(y
0
y
1
) = 2y.x
i
- 2x.y
i
+ (2y + x(2c - 1)) (Equation 6)
This must always be the same sign as y
diff
because x is always +ve (were
going left to right remember. Call it D
i
- the decision criteria.
Simplify Equation 6 by collecting together all the non-index terms and the
real terms into one term - K
K = 2y + x(2c - 1) (Equation 7)
D
i
= x(y
0
y
1
) = 2y.x
i
- 2x.y
i
+ K (Equation 8)
Now only K contains a non-integer term. We can make that term disap-
pear by calculating D
i+1
from D
i
D
i +1
= 2y.x
i
- 2x.y
i
+ c (Equation 9)
Subtract Equation 8 from Equation 9:
D
i +1
- D
i
= 2y.(x
i+1
-

x
i
) - 2x.(y
i+1
-

y
i
) (Equation 10)
But,
x
i+1
= x
i
+1
and we know either:
y
i+1
= y
i
2y.xi+1 - 2x.yi+1 + K
Graphics Primitives 60
or
y
i+1
= y
i
+1
so
D
i +1
= D
i
+ 2y - 2x(y
i+1
- y
i
)
We know that the first value of y (y
0
) from the starting coordinates of the
line. The initial value of D (which is called D
o
) can be derived thus:
c = y
0
- mx
o
= y
0
- (y/x)x
0
D
o
= 2y - x
4.2.3 An implementation of the line drawing algorithms
import java.awt.*;
import javax.swing.*;
//----------------------------------------------------------------
//
//
// File : Gcanvas.java
//
//
//----------------------------------------------------------------
class Gcanvas extends JPanel {
int deltaX;
int deltaY;
int DY2;
int DX2;
int Di;
public void bresenhamLine(int x1, int y1, int x2, int y2,
Graphics g){
deltaX = x2-x1;
deltaY = y2-y1;
DY2 = 2* deltaY;
DX2 = 2* deltaX;
Di = DY2 - deltaX;
int x = x1;
int y = y1;
int prevy;
while (x<x2) {
x++;
prevy = y;
Graphics Primitives 61
if (Di > 0){
y++;
}
g.drawLine(x,y,x,y);
Di = Di + DY2 - (DX2 * (y - prevy));
}//while
}//bresenhamLine
public void bruteLine(int x1, int y1, int x2, int y2, Graphics
g){
int deltaX = x2-x1;
int deltaY = y2-y1;
float m = (float)deltaY/(float)deltaX;
float c = y1 - (m*x1);
for (int x=x1; x<x2; x++){
float floatY = (m*x) + c;
int y = Math.round(floatY);
//System.out.println("DeltaX: " + deltaX + ", del-
taY: " + deltaY + ", m: " + m + ", c: " + c + " x: " + x + " floaty:
" + floatY + ", y: " + y );
g.drawLine(x,y,x,y);
}
}
public void paintComponent(Graphics g){
bruteLine(10,10,40,30,g);
bruteLine(10,10,40,90,g);
bresenhamLine(50,50,150,60,g);
bresenhamLine(50,50,150,120,g);
bresenhamLine(50,50,150,140,g);
bresenhamLine(50,50,150,200,g);// this one will produce
wrong line as its outside of gradient range.
}//paintComponent
}//end of -- Gcanvas -------------------------------------------
Graphics Primitives 62
Figure 33. The output of the line drawing program
4.3 Circles
Several approaches are possible to the problem of getting a computer to
draw a circle. One, which we shall again label the brute force algorithm
works but is computationally intensive, a second (the Digital Differential
Analyzer) dispenses with the need for sine and cosine tables, another, again
due to Bresenham, is elegant, efficient and not at all obvious.
All approaches are based on the equation of a circle (Equation 11) and its
parametric forms (Equation 12 and Equation 13). For a circle centred on the
origin:
x
2
+ y
2
= R
2
(Equation 11)
x = R sin (Equation 12)
y = R cos (Equation 13)
Graphics Primitives 63
Figure 34. The equation of a circle
4.3.1 Brute force
Its simple to write a piece of code (see Example 4 below) which iterates
many values of , directly calculates the x and y values and then plots points
at those coordinates. Regrettably, this is extremely inefficient and also relies
on the availability of sine and cosine tables.
4.3.2 Cheating with 8 arcs
Some saving of calculation (and hence time) can be made by using the
symmetry of the circle. Suppose you have calculated some value for x and y
and plot the appropriate point (x,y). The points (x,-y), (-x,-y), (-x,y), (y,x),
(y,-x), (-y,-x) and (-y,x) will also lie on the circle and can also be plotted.
Figure 35. Efficiency via cheating
The following Java code implements the algorithm.
y
x
R


(x,y)
(x,-y)
(y,-x) (-y,-x)
(y,x)
(-y,x)
(-x,y)
(-x,-y)
O
Graphics Primitives 64
26 public void eightPlot(int x, int y, int xOffset, int yOffset,
Graphics g){
27
28 int xPlot = Math.round(xOffset + x);
29 int yPlot = Math.round(yOffset + y);
30 g.drawLine(xPlot,yPlot,xPlot,yPlot);
31
32 xPlot = Math.round(xOffset + x );
33 yPlot = Math.round(yOffset - y);
34 g.drawLine(xPlot,yPlot,xPlot,yPlot);
35
36
37 xPlot = Math.round(xOffset - x);
38 yPlot = Math.round(yOffset - y);
39 g.drawLine(xPlot,yPlot,xPlot,yPlot);
40
41
42 xPlot = Math.round(xOffset - x);
43 yPlot = Math.round(yOffset + y);
44 g.drawLine(xPlot,yPlot,xPlot,yPlot);
45
46 xPlot = Math.round(xOffset + y);
47 yPlot = Math.round(yOffset + x);
48 g.drawLine(xPlot,yPlot,xPlot,yPlot);
49
50 xPlot = Math.round(xOffset + y );
51 yPlot = Math.round(yOffset - x);
52 g.drawLine(xPlot,yPlot,xPlot,yPlot);
53
54
55 xPlot = Math.round(xOffset - y);
56 yPlot = Math.round(yOffset - x);
57 g.drawLine(xPlot,yPlot,xPlot,yPlot);
58
59
60 xPlot = Math.round(xOffset - y);
61 yPlot = Math.round(yOffset + x);
62 g.drawLine(xPlot,yPlot,xPlot,yPlot);
63 }//eightPlot
Example 3. eightPlot()
Graphics Primitives 65
The use of this symmetry means that values for x and y only need to be
calculated for the octant where 0 < x <= y (the arc indicated above). Start
with x= radius and y=0. Iterate until y=x. As you calculate and plot more
points, 8 arcs grow and eventually meet to form the circle.
Figure 36. 8 arcs a-growing
4.3.3 Digital Differential Analysis - An incremental algorithm
A slightly better (quicker) way of calculating x and y values is the digital
differential analyzer algorithm which doesnt require sine and cosine tables
but instead is based upon calculating the gradient of a circle at a point and
using that to approximate the position of the next point.
Our starting point, is the equation of a circle (of radius R) centred on the
origin:
x
2
+ y
2
= R
2
(Equation 14)
Re-arranging, making y the subject gives:
(Equation 15)
By differentiating this with respect to x, we find that the gradient (m) at
any point on the circle is
(Equation 16)
y R
2
x
2
=
dy
dx
------
x
y
----- m = =
Graphics Primitives 66
Now consider Figure 37:
Figure 37. Basis of the incremental algorithm
Assume that the values of x
i
,y
i
for one point of the circle are known
(given). From them we would ideally like to calculate the values of x and y at
Point T (the true values for x and y at the next point round the circle). In fact,
we can calculate the x and y values at Point A quickly and by making sure
than the distance between successive points () is small, then Point A will lie
close to the true circle.
Equation 16 gives us the gradient (m) of a tangent to the circle, but the
gradient of that tangent is also:
(Equation 17)
For small increments () points T and A are close. i.e.
. (Equation 18)
This is a bit of a cheat to get into the equation, but since it appears in
both numerator and denominator it is obviously true. Thus:
(Equation 19)
and
(Equation 20)
We can chose the value of , so by choosing a small value, then
Ax
i+1
,Ay
i+1
will be (almost) on the circle.
T
x
i 1 +
T
y
i 1 +
, ( )
A
x
i 1 +
A
y
i 1 +
, ( )
x
y

(x
i
,y
i
)
true
approximate
circle
T A
pixel boundaries
y
x
------
A
y
i 1 +
y
i

A
x
i 1 +
x
i

--------------------- m = =
y
x
------
T
y
i 1 +
y
i

T
x
i 1 +
x
i

---------------------
x
i

y
i
----------
A
x
i 1 +
x
i
y
i
+ =
A
y
i 1 +
y
i
x
i
=
Graphics Primitives 67
The value for must be selected to produce a change in x and y of around
1 pixel at a maximum. In practise this can be achieved by selecting such
that:
where
The DDA can be combined with our eightPlot() method to reduce still
further the number of calculations required.
As well as being cool (or an elegant solution if were being more for-
mal), this method is a much more efficient way of calculating the points of a
circle that the brute force approach. It still, however, contains one floating
point division (to work out -x/y) for each point plotted. For absolute effi-
ciency, we need a totally integer based solution and must turn once again to
the work of Bresenham.
4.3.4 Bresenhams algorithm for circles
Like Bresenhams line algorithm, this approach is based on limiting the
choice of the next pixel to be plotted to two alternatives, then creating and
testing a decision variable to determine which alternative is actually plotted.
Whereas Bresenhams line algorithm calculated the errors y
1
and y
0
based on the straight line equation (Equation 2), here we use the equation of
a circle - Equation 14
(Equation 21)
(Equation 22)

1
2
n
----- = 2
n 1
R 2
n
<
D S
i
( ) x
i 1
1 + ( )
2
y
i 1
( )
2
+ [ ] R
2
=
D T
i
( ) x
i 1
1 + ( )
2
y
i 1
1 ( )
2
+ [ ] R
2
=
Graphics Primitives 68
D(S
i
) and D(T
i
) represent the differences between the squared distance
between the centre of the circle and the middle of pixels S and T . Whichever
is smallest corresponds to the pixel that should be plotted.
Figure 38. Distances in the Bresenhams circle algorithm
To combine the two calculations into one decision variable is simply a
matter of subtracting the two expressions:
d
i
= |D(S
i
)| - |D(T
i
)| (Equation 23)
S
T
D S
i
( )
D T
i
( )
S
T
Graphics Primitives 69
We can then make the decision based upon whether d
i
is positive or nega-
tive:
if d
i
> 0 then
plot pixel T
else
plot pixel S
Actually, because the decision is based purely upon the sign of d
i
(and not
its value), Equation 23 can be simplified to
d
i
= D(S
i
) +D(T
i
) (Equation 24)
After some re-arrangement (which is left as a exercise for the reader) the
following can be obtained:
d
i
= 3 - 2R (Equation 25)
If pixel S is chosen (based upon the sign of d
i
in Equation 25 then
d
i+1
= d
i
+4x
i-1
+ 6 (Equation 26)
or if pixel T is chosen
d
i+1
= d
i
+ 4(x
i-1
-y
i-1
) + 10 (Equation 27)
4.3.5 An implementation of the circle drawing algorithms
The code in Example 4 implements the algorithms described above. Only
the Gcanvas class is shown. The resulting output is shown in Figure 39.
import java.awt.*;
import javax.swing.*;
//----------------------------------------------------------------
//
//
// File : Gcanvas.java
//
//
//----------------------------------------------------------------
class Gcanvas extends JPanel {
public void eightPlot(int x, int y, int xOffset, int yOffset,
Graphics g){
int xPlot = Math.round(xOffset + x);
int yPlot = Math.round(yOffset + y);
g.drawLine(xPlot,yPlot,xPlot,yPlot);
Graphics Primitives 70
xPlot = Math.round(xOffset + x );
yPlot = Math.round(yOffset - y);
g.drawLine(xPlot,yPlot,xPlot,yPlot);
xPlot = Math.round(xOffset - x);
yPlot = Math.round(yOffset - y);
g.drawLine(xPlot,yPlot,xPlot,yPlot);
xPlot = Math.round(xOffset - x);
yPlot = Math.round(yOffset + y);
g.drawLine(xPlot,yPlot,xPlot,yPlot);
xPlot = Math.round(xOffset + y);
yPlot = Math.round(yOffset + x);
g.drawLine(xPlot,yPlot,xPlot,yPlot);
xPlot = Math.round(xOffset + y );
yPlot = Math.round(yOffset - x);
g.drawLine(xPlot,yPlot,xPlot,yPlot);
xPlot = Math.round(xOffset - y);
yPlot = Math.round(yOffset - x);
g.drawLine(xPlot,yPlot,xPlot,yPlot);
xPlot = Math.round(xOffset - y);
yPlot = Math.round(yOffset + x);
g.drawLine(xPlot,yPlot,xPlot,yPlot);
}//eightPlot
public void bruteCircle(int x0, int y0, int radius, Graphics
g){
for(int theta=0; theta<45; theta++){
int x = Math.round(radius *
(float)Math.sin(Math.toRadians(theta)));
int y = Math.round(radius *
(float)Math.cos(Math.toRadians(theta)));
eightPlot(x,y,x0,y0,g);
// int xPlot = x0 + x;
// int yPlot = y0 + y;
// g.drawLine(xPlot,yPlot,xPlot,yPlot); //plot a point
@ (xPlot,yPlot)
}
}//bruteCircle
Graphics Primitives 71
public void bresenhamCircle(int x0, int y0, int radius, Graph-
ics g, int fudge){
int x =0;
int y = radius;
int di = 3 - 2*radius;
while(x < y/fudge) {
eightPlot(x,y,x0,y0,g);
if (di <0){
di= di + 4 * x + 6;
} else {
di= di + 4 * (x-y) + 10;
y--;
}
eightPlot(x,y,x0,y0,g);
x++;
}
}//bresenhamCircle
public void incrementalCircle(int x0, int y0, int radius,
Graphics g){
float x = radius;
float y = 0;
int P = 1;
for(int i=1; radius>P; i++) {P *= 2;}
float E = 1/(float)P;
while (y <= x){
x = x + (E*y);
y = y - (E*x);
System.out.println("(" + x + "," + y + ")");
eightPlot(Math.round(x),Math.round(y),x0,y0,g);
}
}//incrementalCircle
Graphics Primitives 72
public void paintComponent(Graphics g){
g.drawString("Brute force algorithm" ,50, 25 );
bruteCircle(100,90,50,g);
bruteCircle(180,90,5,g);
g.drawString("Incremental algorithm" ,50, 185 );
incrementalCircle(100,250,50,g);
incrementalCircle(180,250,10,g);
g.drawString("Bresenham algorithm" ,50, 345 );
bresenhamCircle(100,410,50,g,6);
bresenhamCircle(220,410,50,g,4);
bresenhamCircle(340,410,50,g,2);
bresenhamCircle(460,410,50,g,1);
// bresenhamCircle(60,120,5,g);
}//paintComponent
}//end of -- Gcanvas ---------------------------------------------
Example 4. Implementation of the three circle drawing algorithms
Graphics Primitives 73
Figure 39. The output of the circle drawing program
Graphics Primitives 74
Chapter review - 4
The graphics primitive routines provided by any language are the founda-
tion upon which any graphics program is based. Programmers rarely need to
write there own primitives but the information in this chapter would allow
that task to be performed.
Graphics primitive routines need to be fast, as all graphics programs will
make intensive use of them.
For straight lines an easy to understand but inefficient approach and a
more complex but efficient algorithm known as Bresenhams algorithm have
been presented.
For circles, three algorithms of increasing efficiency have been presented.
4.4 Exercises - 4
4.1 Write a Java program that draws (say) 10,000 random straight
lines using firstly the brute force approach and secondly Bresen-
hams algorithm. Use Javas clock facilities to time the execution
of the two alternatives and demonstrate which is the more effi-
cient. You may have to alter the number of lines drawn to obtain
sensible answers depending on the speed of the computer you
use.
4.2 Repeat the exercise for the three circle generating algorithms.
Data Structures and Drawing 75
Chapter 5
Data Structures and
Drawing
5.1 Introduction
This course in computer graphics is centred on understanding the algo-
rithms used to generate 'on screen' graphics images. The intention is that you
will understand how to program the generation of 2D and 3D images and
how to manipulate those images through scaling, translation, rotation and
projection. You will also learn how to colour and shade the images, remove
hidden surfaces and create realistic lighting effects. Before any of that how-
ever, we must learn more about how to describe a drawing in terms that a
computer can understand.
5.2 The basic 2d data structure
Lets start at the bottom and work our way up. The first class we will
tackle is Point2d.
Data Structures and Drawing 76
5.2.1 Point2d class
The most basic thing we need to represent in graphics is the point. A point
is basically two coordinates, x and y, which are real numbers. This suggests
that we might define a Java class to represent a point that looks something
like this (Figure 40):
Figure 40. The Point2d class and an instance of it.
We shall refer to this class as Point2d to differentiate it from its 3d coun-
terpart which we shall meet later on. The main task that objects of the
Point2d class must accomplish is to store the x and y coordinates of the
point. Thus in Java, the Point2d Class might look something like Example
5:
Example 5. The Point2d class
1 class Point2d{
2
3 public float x = 0;
4 public float y = 0;
5
6 }//end class Point2d
Point2d:
float: x
float: y
Point2d: myPoint
x: -10
y: 10
Data Structures and Drawing 77
5.2.2 Line2d Class
Let us start considering lines by taking a look at a very simple drawing of
a square.
Figure 41. A square
The square has the corners emphasised with blobs since we are going to
refer to the corners as nodes and they have special significance for the data
structure. Notice in the drawing that a line is defined between two nodes (for
example line L1 connects nodes N1 and N2) but not all nodes are connected
by lines (for example N1 is not connected to N3).
We have seen in the Apollo 13 example, that lines are the basic constitu-
ents of drawing, and that each line has two end points. This suggests that an
appropriate way to describe the drawings would be in terms of two classes:
Line2d and Point2d.
L
1
L
2
L
3
L
4
x
y
N
1 N
2
N
3
N
4
(10,10)
(10,-10)
(-10,-10)
(-10,10)
(0,0)
Data Structures and Drawing 78
Thus to represent L
1
in this scheme, we need 3 objects: see Figure 42
Figure 42. Description of line L
1
using objects
In Java we can define the Line2d class like this:
Example 6. Line2d
1 class Line2d {
2
3 private Point2d src;
4 private Point2d dest;
5
6 }//end class Line2d
Line2d: L1
src:
dest:
Point2d: N1
x: -10
y: 10
Point2d: N2
x: 10
y: 10
Data Structures and Drawing 79
Thus an instance diagram of the objects required to describe our whole
square might look like Figure 43.
Figure 43. Data structure for a square
You might at this point say, hang on, how come there are 4 nodes on this
square, but you have 8 Point2d objects - surely your duplicating data un-
necessarily. Well, yes and no. You could do it like Figure 44 and save your-
Line2d: L1
src:
dest:
Point2d: N1
x: -10
y: 10
Point2d: N2
x: 10
y: 10
Line2d: L2
src:
dest:
Point2d: N2a
x: 10
y: 10
Line2d: L4
src:
dest:
Point2d: N4a
x: -10
y: -10
Point2d: N1a
x: -10
y: 10
Line2d: L3
src:
dest:
Point2d: N3a
x: 10
y: -10
Point2d: N4
x: -10
y: -10
Point2d: N3
x: 10
y: -10
Data Structures and Drawing 80
self 4 objects, but that means that those lines share instances of the points
and CAN NEVER BE CHANGED INDEPENDANTLY. From a data model-
ling point of view, the corners of the square are in fact two points that JUST
HAPPEN to be in the same place.
Figure 44. Alternative but problematic way of organising structure
It is conceivable that during the execution of the program, you might want
to change those lines into a completely different shape. With the original,
resource hungry version, you have that flexibility available.
Line2d: L1
src:
dest:
Point2d: N1
x: -10
y: 10
Point2d: N2
x: 10
y: 10
Line2d: L2
src:
dest:
Point2d: N3
x: 10
y: -10
Line2d: L4
src:
dest:
Line2d: L3
src:
dest:
Point2d: N4
x: -10
y: -10
Data Structures and Drawing 81
5.2.3 Shape2d class
We can generalise this a bit by saying that any shape can be described as a
collection of lines. We, therefore introduce another class, Shape2d, which
maintains a list of all of the lines that make up a shape. This could be imple-
mented in many ways, in fact we shall use a Vector which we will call
lines.
Figure 45. Basic 2d data structure
In addition, it is useful to know how many lines make up our shape. We
use and integer named numberOfLines to keep count. Again, in Java, this
would look something like this:
Example 7. Shape2d in Java
1 class Shape2d{
2
3 private Vector lines = new Vector();
4 private int numberOfLines=0;
Point2d
x:
y:
Shape2d: mySquare
lines:
Line2d: L
1
src:
dest:
Line2d: L3
src:
dest:
Line2d: L
2
src:
dest:
Line2d: L4
src:
dest:
Point2d
x:
y:
Data Structures and Drawing 82
5
6 }//end class Shape2d
5.2.4 Drawing2d class
A drawing can (obviously?) consist of many shapes - Example 46. We can
therefore add a final class to our data model: Drawing2d, which can maintain
another list (Vector) of the various shapes.
Figure 46. 2nd example diagram
L
1
L
2
L
3
L
4
x
y
N
1 N
2
N
3
N
4
(10,10)
(10,-10)
(-10,-10)
(-10,10)
(0,0)
N
5
N
6
N
7
Data Structures and Drawing 83
Figure 47. Basic 2d data structure
Example 8. Drawing2d in Java
1 class Drawing2d {
2
3 private Vector shapes = new Vector();
4 int numberOfShapes=0;
5
6 }//Drawing2d
So, in full, we have a drawing object, which has a list of shape objects,
which have lists of line objects, which have two point objects each. This can
be shown as an instance diagram - Figure 48, or slightly more formally as a
class diagram - Figure 49
Drawing2d: myDrawing
shapes:
Shape2d: mySquare
lines:
Shape2d: myArrow
lines:
Data Structures and Drawing 84
Figure 48. Summary instance diagram of the basic 2d data structure
Figure 49. Class diagram of the basic 2D data structure
Drawing2D
Shape2d Shape2d
Line2d Line2d Line2d Line2d Line2d Line2d
Point2d Point2d Point2d Point2d Point2d Point2d
mySquare
myArrow
Drawing2D Shape2d Line2d Point2d
1 M 1 M
1 1
1 1
src
dest
lines shapes
Data Structures and Drawing 85
Now all we have to do is work out what methods we need to do the draw-
ing, and fit this into our structure of a simple graphics application and work
out how the whole lot gets constructed in the first place. Simple really.
5.3 Adding methods
At the moment, our classes are capable of storing data about graphics, but
they are missing two things:
a means of actually assembling a structure from the classes. We
need to add constructors and accessor methods
any drawing functionality we need to add the actual commands
which cause things to be displayed on the screen.
5.3.1 Point2d class
The main task that objects of the Point2d class must accomplish is to store
the x and y coordinates of the point. To turn our existing version into some-
thing useful, we need a constructor to allow us to actually make objects and
two methods which allow us access to the data inside the class:
Example 9. a working Point2d class
1 class Point2d{
2
3 public float x = 0;
4 public float y = 0;
5 private float k = 1;
6
7 public Point2d(float in_x, float in_y) {
8 x = in_x;
9 y = in_y;
10 }// end constructor
11
12 public float x() {
13 return (x);
14 }
15
16 public float y() {
17 return (y);
18 }
19
20 }//end class Point2d
If we now wanted to use the Point2d class in a program, we could write
something like:
Data Structures and Drawing 86
Point2d myPoint = new Point2d(100,150);
The newly created point object will now faithfully remember our coordi-
nates for us. We can even ask it to tell us what it was we asked it to remember
System.out.println (( + myPoint.x() + , + myPoint.x() + ));
5.3.2 Line2d Class
Line2d needs a constructor and a means of actually drawing lines:
Example 10. a working Line2d class
1 import java.awt.*;
1
1
2 class Line2d {
3
4
5 private Point2d src;
6 private Point2d dest;
7
8
9 public Line2d (float x1, float y1, float x2, float y2) {
10 src = new Point2d(x1,y1);
11 dest = new Point2d(x2,y2);
12 }//end constructor
13
14
15 public void draw(Graphics g){
16
17 g.drawLine((int)src.x(), (int)src.y(), (int)dest.x(),
(int)dest.y());
18 }//end draw
19
20
21 }//end class Line2d
22
The constructor takes two sets or coordinates and uses them to set up its
two points. The draw method is responsible for actually putting something
on screen. It uses the drawLine() method of the Graphics class that we are
familiar with from the Apollo13 example.
Since we are using the Graphics class, we must import java.awt.* (see
line 1) to make that class available to us.
Data Structures and Drawing 87
5.3.3 Shape2d class
A means is needed of adding lines to shapes. To this end we can add a
method called addLine() to our Shape2d class. Its job is to add a line to the
list of lines that make up a particular shape. In fact we can add two versions
of this method; the first takes a ready made Line2d object as a parameter and
just adds it to our list, the second takes in the coordinates of a line, constructs
it for us and then adds it to the list. We need to keep track of how many lines
make up each shape, so when ever a line is added to the lines Vector, we
add 1 to the variable called numberOfLines.
To actually draw a Shape2d on the screen, all we need to do is to tell each
line that make up the shape to draw itself. That is exactly what method draw
does. It uses a for loop to go through all of the lines and call each ones draw
method. Effectively, Shape2d.draw() delegates the job of drawing to each
line. See line 26 - which looks quite horrible, but is in fact, just us telling
each line to draw itself.
Example 11. a working Shape2d class
1 import java.util.*;
2 import java.awt.*;
3
4 class Shape2d{
5
6 private Point2d localOrigin = new Point2d(0,0);
7 private Vector lines = new Vector();
8 private int numberOfLines=0;
9
10
11 public void addLine(Line2d inLine){
12 lines.add(inLine);
13 numberOfLines = numberOfLines + 1;
14 }//end addLine
15
16
17 public void addLine(float x1, float y1, float x2, float y2){
18 Line2d myLine = new Line2d(x1, y1, x2, y2);
19 lines.add(myLine);
20 numberOfLines = numberOfLines + 1;
21 }//end addLine
22
23
24 public void draw(Graphics g){
25 for (int i=0; i < numberOfLines; i = i+1) {
26 ((Line2d)lines.get(i)).draw(g);
27 }//end for i
28
29
30 }//end draw
31
Data Structures and Drawing 88
32
33 }//end class Shape2d
Lines 1 and 2 simply make sure that the Vector and Graphics classes are
available to us.
5.3.4 Drawing2d class
The Drawing2d class is very similar to the Shape2d class. In the same
way as we need to be able to add lines to shapes, so we need to add shapes to
drawings, hence the function addShape() (lines 10-13) Compare this to add-
Line in the previous example.
Similarly, in order to draw a complete drawing, we just need to pass the
drawing request on to all constituent shapes: (c.f. shapes -> lines)
Example 12. a working Drawing2d class
1 import java.util.*;
2 import java.awt.*;
3
4 class Drawing2d {
5
6 private Vector shapes = new Vector();
7 int numberOfShapes=0;
8
9
10 public void addShape(Shape2d inShape){
11 shapes.add(inShape);
12 numberOfShapes = numberOfShapes + 1;
13 }//end addShape
14
15
16 public void draw(Graphics g){
17 for (int i=0; i < numberOfShapes; i = i+1) {
18 ((Shape2d)shapes.get(i)).draw(g);
19 }//end for i
20 }//end draw
21
22
23 }//Drawing2d
Lines 1 and 2 simply make sure that the Vector and Graphics classes are
available to us.
Data Structures and Drawing 89
5.3.5 Adding these classes to the simple drawing application
The classes that we have just created are real, we can use them in a
working program. By themselves, they dont actually form a complete pro-
gram (no main() function anywhere!). To make something that actually runs
and draws on screen, we need to merge these classes into the simple graphics
application that we have previously seen as the Apollo13 example.
First of all, we modify our Gapp. This version of Gapp is EXACTLY
THE SAME as the one we used for Apollo13 APART FROM lines 6-10 and
the constructor.
Example 13. A working Gapp
1 import java.awt.*;
2 import java.awt.event.*;
3 import javax.swing.*;
4
5
6 public class Gapp extends JFrame {
7 private Shape2d myShape = new Shape2d();
8 private Drawing2d myDrawing = new Drawing2d();
9 private Gcanvas myGcanvas = new Gcanvas();
10
11
12 public Gapp(){
13 setBackground(Color.white);
14 myDrawing.addShape(myShape);
15 myGcanvas.setDrawing(myDrawing);
16 myShape.addLine((float)50, (float)50, (float)50, (float)150);
17 myShape.addLine((float)50, (float)100, (float)100, (float)100);
18 myShape.addLine((float)100, (float)100, (float)100,
(float)150);
19 myShape.addLine((float)150, (float)150, (float)150,
(float)100);
20 }// constructor
21
22
23
24
25 public void initComponents() throws Exception {
26 setLocation(new java.awt.Point(0, 30));
27 setSize(new java.awt.Dimension(650, 400));
28 setTitle("Graphics Application");
29 getContentPane().add(myGcanvas);
30 addWindowListener(new java.awt.event.WindowAdapter() {
31 public void windowClosing(java.awt.event.Window-
Event e) {
32 thisWindowClosing(e);
33 }
34 });
35 }//end - initComponents
Data Structures and Drawing 90
36
37
38
39
40 void thisWindowClosing(java.awt.event.WindowEvent e){
41 // Close the window when the close box is clicked
42 setVisible(false);
43 dispose();
44 System.exit(0);
45 }//end - thisWindowClosing
46
47
48
49
50
51 static public void main(String[] args) {
52 // Main entry point
53 try {
54 Gapp myGapp = new Gapp();
55 myGapp.initComponents();
56 myGapp.setVisible(true);
57 }
58 catch (Exception e) {
59 e.printStackTrace();
60 }
61 }//end main
62
63
64 }//end of class - Gapp1
Gcanvas has now acquired a variable called myDrawing which holds an
instance of the Drawing2d class.
The paintComponent() function has been simplified, it simply asks
myDrawing to draw itself (which in turn asks all of the shape objects, which
ask the line objects).
Example 14. A working Gcanvas
1 import java.awt.*;
2 import javax.swing.*;
3
4 class Gcanvas extends JPanel {
5
6 private Drawing2d myDrawing;
7
8
9 public void setDrawing(Drawing2d inDrawing) {
10 myDrawing = inDrawing;
11 }
12
Data Structures and Drawing 91
13
14
15 public void paintComponent(Graphics g){
16 myDrawing.draw(g);
17 }//paintComponent
18
19 }//Gcanvas
5.4 The completed system
The final class diagram of the system should look something like
this.(Figure 50)
Figure 50. The design of a simple graphics application
Drawing2D
Shape2d
Line2d
Point2d Point2d
JFrame
Gapp Gcanvas
JPanel
JDK - swing
ours
initComponents
thisWindowclosing
paintComponent
Data Structures and Drawing 92
5.5 The Dry Run
Try dry-running this program by following the execution of the code.
Draw the objects as they are created and added to the data structure. Draw
the output by running through the paintComponent() method
Aside Dry running is an invaluable technique for understanding, explaining and
debugging code. It can be very involved and requires concentration, but is
often the only way to REALLY understand what a piece of code does. If
youve never dry run a piece of code, try this now. Youll be a better
programmer for it.
5.6 Further methods
5.6.1 Drawing vs erasing
Suppose you want to change something on your drawing. What you need
is an erase method in the Line2D class. It will need to be exactly the same as
the draw method, but it will need to set the current drawing colour to the cur-
rent background colour (usually white) before it draws its line. Shape2D will
also need an erase method, which simply calls the erase method of all its
constituent shapes. More details are given in section 8.2.1.
Data Structures and Drawing 93
Chapter review - 5
In this chapter you should have learned about:
How to represent a drawing in terms of point, line, shape and
drawing objects
How those classes can be implemented in Java
How to add methods to those classes which allow them to be
assembled into useful structures
How to add methods which cause the drawings to be displayed on
screen.
Data Structures and Drawing 94
Exercises - 5
5.1 Get the example program from this chapter to work. Hint - copy
the Gapp and Gcanvas files from the last exercise
5.2 Modify the constructor of the Gapp class to draw something
more interesting e.g:
5.3 Define outstaring() methods for Point2d, Line2d, Shape2d
and Drawing2d. Use them to produce a print out of the data used
to construct your drawings. Your printout should look something
like this:
Drawing2d(
Shape2d(
Line2d(
src: Point2d(100,50)
dest: Point2d(50,200)
)endLine2d
Line2d(
src: Point2d(300,300)
dest: Point2d(200,200)
)endLine2d
)endShape2d
Shape2d(
Line2d(
src: Point2d(22,43)
dest: Point2d(82,43)
)endLine2d
)endShape2d
)endDrawing
The rest of these section 5 exercises are optional as they arent strictly
necessary to an understanding of graphics. However, if your Java skills are
up to it, they are extremely useful techniques to master
5.4 Develop a method that writes your drawing data out to file
(effectively a means of saving your drawing)
5.5 Develop methods that read the drawing data file, load the data
back into a data structure and display it. This, in effect requires
the construction of a simple parser.
2d Transformations 95
Chapter 6
2d Transformations
6.1 Introduction
You may, with some justification, be wondering what was achieved by
turning the simple Apollo13 program into the more complicated Basic2d
application. Well, so far all of the work we have done has just been setting
the scene - putting in place a Java framework that will allow us to deal with
graphical information. Now we can actually start to work with that informa-
tion, to manipulate it, to TRANSFORM it
We shall look at transformation in two ways:
a simple way which introduces the concept and shows a simple
way of programming them.
a more complex, more powerful and more computational efficient
way of representing them
6.2 Transformations the simple way
6.2.1 What is a transformation?
Exactly what it says - an operation that transforms or changes a shape
(line, drawing etc.) They are best understood graphically first. There are sev-
eral basic ways you can change a shape: translation (moving it somewhere
else), rotation (turning it round) and scaling (making it bigger or smaller).
There are man
2d Transformations 96
y others, but well worry about them later.
6.2.2 Translation
Consider the arrow shown in Figure 51. We may want to move it from
position A to position B.
Figure 51. Translation
Essentially, we want to move the shape dx pixels along the x-axis and dy
pixels up the y-axis. In fact all this means is moving each constituent point
by dx and dy.
To move a point in this manner, simply add the values of dx and dy to its
existing coordinates. Example 15 shows what a translate() method of the
Point2D class might look like.
Example 15. Point2d.translate()
1 public void translate(float dx, float dy){
2 x = x + dx;
3 y = y + dy;
4 }
Aside It is worth pointing out the obvious; that if you want to move the shape left,
then use a negative value for dx and likewise for down and dy!
A
B
dx
dy
x
y
2d Transformations 97
To translate a line, simply translate both of its end points:
Example 16. Line2d.translate()
1 public void translate(float dx, float dy){
2 src.translate(dx,dy);
3 dest.translate(dx,dy);
4 }//end translate
Note: No maths is involved anywhere other than in the Point2d class.
Translating the higher order objects is simply a case a passing on the
request to move to the constituent objects. The same applies to shapes and
drawings:
Example 17. Shape2d.translate()
1 public void translate(float dx, float dy){
2 for (int i=0; i < numberOfLines; i = i+1) {
3 ((Line2d)lines.get(i)).translate(dx,dy);
4 }//end for i
5 }//end translate
Example 18. Drawing2d.translate()
1 public void translate(float dx, float dy){
2 for (int i=0; i < numberOfShapes; i = i+1) {
3 ((Shape2d)shapes.get(i)).translate(dx,dy);
4 }//end for i
5 }//end translate
2d Transformations 98
6.2.3 Rotation - (about the origin)
Consider arrow B which we wish to rotate through an angle of 45 anti-
clockwise from A
Figure 52. Rotation
The first thing to note is that any rotation must take place about a point
which remains stationary. In this case, we are simply rotation the shape about
the origin. This is, in fact, a special case (it makes the maths easier) and we
shall see how to rotate a shape about some arbitrary point later on. To rotate
any shape about the origin requires rotating each of its individual points. To
work out how this is done, consider the coordinates of a point before and
after the rotation: Both points will lie on the perimeter of a circle of radius r
with its centre on the origin. See Figure 53:
A
B
45
x
y
2d Transformations 99
Figure 53. Rotating a single point
Time for some trigonometry:
x
2
= r cos ( + )
y
2
= r sin ( + )
x
2
= r (cos cos - sin sin )
since x
1
= r cos and y
1
= r sin
x
2
= x
1
cos - y
1
sin (Equation 28)
similarly: y
2
= x
1
sin + y
1
cos (Equation 29)
Stick this knowledge into a program, and you get this:
Example 19. rotation of a point in Java
1 public void rotate(float a) {
1 float xtemp;
2 xtemp = (x * (float)Math.cos(a)) - (y * (float)Math.sin(a));
3 y = (x * (float)Math.sin(a)) + (y * (float)Math.cos(a));
r
(x
1
,y
1
)
(x
2
,y
2
)

x
y
2d Transformations 100
4 x = xtemp;
5 }
As with translation, applying the rotation transformation to the higher
order objects is simply a matter of making sure that the request gets passed
down the data structure to the appropriate points:
Example 20. Line2d.rotate(float a)
1 public void rotate(float angle){
2 src.rotate(angle);
3 dest.rotate(angle);
4 }//end rotate
Example 21. Shape2d.rotate(float a)
1 public void rotate(float angle){
2 for (int i=0; i < numberOfLines; i = i+1) {
3 ((Line2d)lines.get(i)).rotate(angle);
4 }//end for i
5 }//end translate
Example 22. Drawing2d.rotate(float a)
1 public void rotate(float angle){
2 for (int i=0; i < numberOfShapes; i = i+1) {
3 ((Shape2d)shapes.get(i)).rotate(angle);
4 }//end for i
5 }//end translate
6
Aside Angles in Java are specified in radians not degrees 360 = 2 rad
angle_in_radians = angle_in_degrees * Math.PI / 180;
or
angle_in_radians = Math.toRadians(angle_in_degrees);
Aside Rotation is measured in an anticlockwise direction. To turn a shape the other
way, specify a negative value for the angle.
2d Transformations 101
6.2.4 Scaling
Scaling a shape simply means making a it bigger or smaller. We can spec-
ify how much bigger or small be means of a scale factor - to double the
size of an object we use a scale factor of 2, to half the size of an object we
use a scale factor of 0.5.
Figure 54. Scaling
Again, scaling of a shape is achieved by applying an operation to the indi-
vidual points that make up the shape. In this case, the distance of a point
from the origin changes by the scale factor.
Figure 55. Scaling an individual point.
A
B
x
y
A
B
x
1
y
1
x
2
x
y
y
2
2d Transformations 102
Simply multiplying the coordinates by the scale factor gives the new val-
ues of the coordinates
x
2
= x
1
* sf (Equation 30)
y
2
= y
1
* sf (Equation 31)
Note that the scaling can be different in different directions: i.e. the x
scale factor can be different to the y scale factor. By doing this we can stretch
or squeeze a shape:
Figure 56. The independence of axes for scaling
The implementation of this in Java gives us the following scale()
method:
Example 23. Point2d.scale()
1 public void scale(float xScale, float yScale) {
2 x = x * xScale;
3 y = y * yScale;
4 }
A
B
A
B
x
sf
= 4
y
sf
= 1
x
sf
= 1
y
sf
= 4 (ish)
2d Transformations 103
The use of the method in the higher order classes follows the same pattern
as translate() and rotate() and is therefore deliberately left for you to
work out.
6.2.5 Identity transformations
Some transformations lead to no change in the shape/line/point:
translate (0,0)
rotate (2 * Math.PI)
scale (1,1)
2d Transformations 104
6.2.6 Order of transformations
The order in which transformations are applied to a shape is important.
e.g. performing a translation followed by a rotation, will give an entirely dif-
ferent drawing to a performing the rotation followed by the same translation.
- (Figure 57)
Figure 57. Order of Transformations
x
y
x
rotation by 45 followed by translation (100,0)
translation (100,0) followed by rotation by 45
y
2d Transformations 105
6.2.7 Rotation around local origin
At the moment, our rotation is centred around the origin. What is often
required is to spin the shape in-situ. - (Figure 58)
Figure 58. Local rotation
This can be achieved by combining two of our existing transformations:
Translate the shape to the origin, rotate it the required amount about the ori-
gin and translate it back to where it was.
x
y
local origin
2d Transformations 106
)
Figure 59. Local rotation
x
y
x
y
x
y
x
y
dy
dx
+dy
+dx
translate(-dx,-dy)
rotate(angle)
translate(dx,dy)
2d Transformations 107
To do this, we need to know exactly which point the shape is to be rotated
around. It is necessary, therefore to introduce the concept of a local origin
to the Shape2d class.
Example 24. The local origin in class Shape2d
1 class Shape2d{
2
3 private Point2d localOrigin = new Point2d(0,0);
4 private Vector lines = new Vector();
5 private int numberOfLines=0;
6
7 public void addLine(Line2d inLine){
8 lines.add(inLine);
9
10 .
11 .
12 .
13 .
When the shape is transformed by any of the transformations we have
seen so far, we must ensure that the local origin is subject to the same trans-
formations. i.e. it must be moved along with all the lines. We can add a line
of code (Example 25 - line 5) to the translate method. A similar line must
be added to scale, rotate and any other transformations that may have been
developed.
Example 25. Transforming the local origin
1 public void translate(float dx, float dy){
2 for (int i=0; i < numberOfLines; i = i+1) {
3 ((Line2d)lines.get(i)).translate(dx,dy);
4 }//end for i
5 localOrigin.translate(dx,dy);
6 }//end translate
When the shape is first created, in addition to specifying all of the constit-
uent lines, the local origin (or middle of the shape) must also be given.
Example 26. Defining the local origin
1 apollo13 = new Shape2d(150,100);
2 apollo13.addLine((float)50, (float)50, (float)50, (float)150);
3 apollo13.addLine((float)50, (float)150, (float)100, (float)100);
4 apollo13.addLine((float)100, (float)100, (float)100, (float)150);
2d Transformations 108
5 apollo13.addLine((float)100, (float)150, (float)200, (float)150);
6 apollo13.addLine((float)200, (float)150, (float)200, (float)50);
7 apollo13.addLine((float)200, (float)50, (float)100, (float)50);
8 apollo13.addLine((float)100, (float)50, (float)100, (float)100);
9 apollo13.addLine((float)100, (float)100, (float)50, (float)50);
10 apollo13.addLine((float)200, (float)50, (float)250, (float)100);
11 apollo13.addLine((float)250, (float)100, (float)200, (float)150);
12 myDrawing.addShape(apollo13);
Aside Local rotation is only meaningful at the shape level. The operation is not
defined at line or point level.
The actual code to perform the local rotation is given as Example 27
Example 27. Local rotation as implemented in Shape2d
1 public void localRotate(float angle) {
2 float dx = localOrigin.x();
3 float dy = localOrigin.y();
4 translate(-dx,-dy);
5 rotate(angle);
6 translate(dx,dy);
7 }//end localRotate
6.2.8 Other transformations - general cases/ special cases.
From the section on local rotation it can be seen that both local rotation
and rotation about the origin are, in fact, special cases of rotation about an
arbitrary point. The general recipe for this is to translate the shape by an
amount equal to the coordinates of the point of rotation but in a direction
such that the point of rotation ends up at the origin. Perform the rotation, re-
translate the shape by the same amount as before, but in the reverse direction.
The formalisation of this algorithm and its implementation is left as an exer-
cise for the reader.
There are many other possible transformations including: reflection,
reflection in an arbitrary line, shearing etc.
2d Transformations 109
Chapter review - 6
This chapter has
introduced the concepts of transformations:
- translation
- scaling
- rotating
covered how to:
- Manipulate graphics on screen by transformations such as
translation, rotation and scaling
- Implement those transformations simply using methods
Discussed the difference between rotation about the origin and
local rotation
Discussed the importance of transformation order
2d Transformations 110
Exercises - 6
6.1 Modify the Basic2d program to include functions to translate,
rotate and scale points, lines, shapes and drawings.
6.2 Use it to produce something like this:
Transformations as matrices 111
Chapter 7
Transformations as
matrices
7.1 Introduction
It is useful, for reasons that will become apparent later, to represent trans-
formations using a matrix notation. Before we examine the useful tricks that
this technique opens up to us, lets first see how it actually works.
7.2 The Transformations
7.2.1 Rotation
If we regard the point P as a vector from the origin defined by (x,y) then
the two equations representing rotation (Equation 28 + Equation 29) can be
written in matrix form:
If p and p represent the point P before and after rotation and R the rota-
tion matrix, we can write the equation above more succinctly:
p = R.p (EQ 32)
x
y


cos sin
sin cos


x
y


=
Transformations as matrices 112
7.2.2 Scaling
Similarly the scaling equations can be converted to:
or
p = S.p (EQ 33)
7.2.3 Translation
Once again, for translation:
or
p = T + p (EQ 34)
7.2.4 Homogenous coordinates
One useful consequence of using matrices is that transformations that are
combinations of transformations (remember that a local rotation is equiva-
lent to a translation followed by a rotation followed by a translation) can be
represented by multiplying the matrices together. Unfortunately, with the
current set a matrices, this wont work because Equation 32 & Equation 33
are multiplications, whilst Equation 34 is an addition. We can get round this
by effectively including a fiddle factor and converting the matrices to use
homogenous coordinates. What this actually means is that the addition
necessary to perform translation can be achieved by multiplication. (Well
prove this in a moment.) To convert our scheme of representation to homog-
enous coordinates we add an extra row to all point matrices and fill the extra
position with a 1.
We then adapt our transformation matrices as below:
x
y
xsf 0
0 ysf
x
y
=
x
y
dx
dy
x
y
+ =
x
y
1
Transformations as matrices 113
7.2.5 Homogenous rotation
7.2.6 Homogenous scaling
7.2.7 Homogenous translation
Since everything is now done by multiplication, all the vector forms of
these equations have the same form including translation:
p = T.p (EQ 35)
7.3 Implementing Matrices
A matrix class can be implemented as follows:
Example 28. The Matrix class
1 class Matrix {
2
3 public int rows = 0;
4 public int columns = 0;
5 public float [][] m;
6
7
8 Matrix(int in_rows, int in_columns, float val){
9 rows=in_rows;
10 columns=in_columns;
11 m = new float [rows][columns];
12 for (int i = 0; i < rows; i++ ) {
x
y
1
( ) cos ( ) sin 0
( ) sin ( ) cos 0
0 0 1
x
y
1
=
x
y
1
xsf 0 0
0 ysf 0
0 0 1
x
y
1
=
x
y
1
1 0 dx
0 1 dy
0 0 1
x
y
1
=
Transformations as matrices 114
13 for (int j = 0; j < columns; j++ ) {
14 m[i][j] = val;
15 }//end for j
16 }//end for i
17 }//constructor
18
19
20
21 public Matrix (float [][] in_data) {
22 rows = in_data.length;
23 columns = in_data[0].length;
24 for (int i = 0; i < rows; i++) {
25 if (in_data[i].length != columns) {
26 throw new IllegalArgumentException("All rows must
have the same length.");
27 }
28 }
29 m = in_data;
30 }//constructor
31
32
33
34 public int getRows(){
35 return (rows);
36 }//
37
38
39 public int getColumns() {
40 return (columns);
41 }
42
43
44 public float getElement(int i, int j){
45 return(m[i][j]);
46 }
47
48
49 public void setElement(int i, int j, float value){
50 m[i][j] = value;
51 }
52
53
54 public Matrix mult(Matrix b){
55 float sum = 0;
56 int i,j,k;
57 if (rows != b.columns) {
58 throw new IllegalArgumentException("Matrices are not
conformable.");
59 }
60 Matrix result = new Matrix(b.rows,columns,0);
61 for (i=0; i < b.rows; i++) {
62 for (j=0; j < columns; j++){
63 sum = 0;
64 for (k=0; k<rows; k++){
65 sum = sum + b.getElement(i,k)*m[k][j];
66 }//end for k
67 result.m[i][j]=sum;
Transformations as matrices 115
68 }//end for i
69 }//end for j
70 return result;
71 }//end mult
72
73
74
75 public void transform(Matrix b) {
76 float sum = 0;
77 int i,j,k;
78 if (rows != b.columns) {
79 throw new IllegalArgumentException("Matrices are not
conformable.");
80 }
81 float [][] result = new float[b.rows][columns];
82 for (i=0; i < b.rows; i++) {
83 for (j=0; j < columns; j++){
84 sum = 0;
85 for (k=0; k<rows; k++){
86 sum = sum + b.getElement(i,k)*m[k][j];
87 }//end for k
88 result[i][j]=sum;
89 }//end for i
90 }//end for j
91 m=result;
92 }
93
94
95
96 public String toString(){
97 String result = new String("[");
98 for (int i = 0; i < rows; i++ ) {
99 result += "(";
100 for (int j = 0; j < columns; j++ ) {
101 result += m[i][j];
102 if (j != (columns-1)) {
103 result += ", ";
104 }//end if
105 }//end for j
106 result += ")\r";
107 }//end for i
108 result += "]";
109 return(result);
110 }// toString
111
112
113
114 }//end of class Matrix
Aside The eagle-eyed reader will have spotted that two methods in the
implementation above perform matrix multiplication, namely multiplication
and transform. The difference between the two is that multiplication returns a
new matrix object that holds the result of the multiplication whilst transform
return nothing, but the state of the matrix to which the operation was applied
Transformations as matrices 116
is changed to reflect the result.
Aside As an alternative to this home made solution, a fully featured matrix
mathematics package exists. Named JAMA it can be found at http://
math.nist.gov/javanumerics/jama/
7.4 Using the matrix class
We need to change our implementation of points. Let Point2d inherit
matrix:
Example 29. Point2d with matrices
1 class Point2d extends Matrix{
2
3 public Point2d(float in_x, float in_y) {
4 super(3,1,1);
5 m[0][0]=in_x;
6 m[1][0]=in_y;
7 }// end constructor
8
9
10
11 public float x() {
12 return (m[0][0]);
13 }
14
15
16 public float y() {
17 return (m[1][0]);
18 }
19 }//end class Point2
We also need a new class - Transformation2d - which also inherits
matrix. Start to think of transformations as things rather than operations -
applying a transformation object to a drawing, shape, line etc.
Example 30. Transformation2d
1 class Transformation2d extends Matrix{
2
3 Transformation2d(){
4 super(3,3,0);
5 m[0][0]=1;
6 m[1][1]=1;
Transformations as matrices 117
7 m[2][2]=1;
8 }//constructor
9
10
11 public void translate(float x, float y) {
12 m[0][2]=x;
13 m[1][2]=y;
14 }//translate
15
16
17 public void rotate(float angle) {
18 m[0][0] = (float)Math.cos(angle);
19 m[1][0] = -(float)Math.sin(angle);
20 m[0][1] = (float)Math.sin(angle);
21 m[1][1] = (float)Math.cos(angle);
22 }//rotate
23
24 }//end class Transformation2d
25
We can remove all of the separate translate, rotate, scale etc. methods
from Line2d, Shape2d and Drawing2d. They can be replaced with a single
transform method:
Example 31. Line2d.transform()
1 public void transform(Transformation2d trans) {
2 src.transform(trans);
3 dest.transform(trans);
4 }//end transform
Example 32. Shape2d.transform()
1 public void transform(Transformation2d trans) {
2 for (int i=0; i < numberOfLines; i = i+1) {
3 ((Line2d)lines.get(i)).transform(trans);
4 }//end for i
5 localOrigin.transform(trans);
6 }//end transform
Transformations as matrices 118
7.4.1 Simple transformation using a matrix
We can now use our new matrix machinery in an example simple transfor-
mation:
Example 33. Simple transformation with matrices
1 public Gapp(){
2
3 setBackground(Color.white);
4
5 myDrawing.addShape(myShape);
6 myGcanvas.setDrawing(myDrawing);
7
8 myShape.addLine((float)50, (float)50, (float)50, (float)150);
9 myShape.addLine((float)50, (float)100, (float)100, (float)100);
10 myShape.addLine((float)100, (float)100, (float)100,
(float)150);
11 myShape.addLine((float)150, (float)150, (float)150,
(float)100);
12
13
14 Transformation2d myTrans = new Transformation2d();
15 myTrans.rotate((float)(10*(3.14159262/180)));
16 myTrans.translate(300,100);
17
18 myDrawing.transform(myTrans);
19 }// constructor
7.4.2 Combination of transformations using matrices
When two matrices that represent different transformations are multiplied
together, the resulting matrix represents the combined transformation. This
leads to one of the main advantages of the matrix representation method: that
a single matrix can be used to store the transformation that results from per-
forming a sequence a transformations. i.e. we can concatenate transfoma-
tions. This has obvious efficiency implications: in the case of repetitively
applying the a series of transformations, the computer will need to do fewer
calculations if the concatention is available. A good example of this is the
need to repeatedly spin an object about its centre (rotation about the local ori-
gin).
Example 34. rotation about local origin using matrices
1 float dx=apollo13.x();
2 float dy=apollo13.y();
Transformations as matrices 119
3
4 Transformation2d transform1 = new Transformation2d();
5 Transformation2d spin = new Transformation2d();
6 Transformation2d translate1 = new Transformation2d();
7 Transformation2d translate2 = new Transformation2d();
8
9 translate1.translate(-dx,-dy);
10 spin.rotate((float)(-10 * Math.PI/180));
11 translate2.translate(dx,dy);
12
13 transform1.transform(translate1);
14 transform1.transform(spin);
15 transform1.transform(translate2);
16
17 myTrans=transform1;
18
Transformations as matrices 120
Chapter review - 7
This chapter has covered:
How to represent transformations as matrices and how to imple-
ment a matrix class in Java.
The use of homogenous coordinates to enable translation to be
performed by multiplication.
The concatenation of transformation by multiplication of matrices
How adapt our existing classes to use a matrix based representa-
tion technique.
Transformations as matrices 121
Exercises - 7
7.1 Develop and test a Java class to represent Matrices. As a mini-
mum, the class should allow the multiplication of matrices.
7.2 Modify the Point2d class you have used in previous exercises to
use a homogenous coordinate matrix representation.
7.3 Develop a Transformation class to represent transformations as
matrices using the homogenous coordinate system.
7.4 Modify the basic 2d program to include functions to transform
points, lines, shapes and drawings.
7.5 Derive and implement the homogenous matrices to represent the
following transformations:
Translation
Rotation about the origin
Scaling
Rotation about the local origin
Reflection in the x axis
Reflection in y=x
Simple Animation and Interaction 122
Chapter 8
Simple Animation and
Interaction
8.1 Introduction
At the moment we can transform shapes etc., but dont see it happen on
screen; all the changes happen off stage, all we see are the results. It is use-
ful to be able to see the changes happen under our control. Useful graphics
programs can be written which dont require user interaction - screen savers
etc., but by allowing the user to interact in some way with the diagram,
whole new vistas can be opened up.
We need, therefore to master two techniques: acquiring user input (so we
tell the program when and how to change our drawing) and animation to
make the changes happen on stage.
We shall discuss two types of animation/interaction - discrete and contin-
uous. In discreet animation, the screen is redrawn (repainted) in response to
some specific user action which usually also involves a single change to the
data structure. With this kind of animation the drawing suddenly jumps
from one state to another. It would be nice to see it gradually change - i.e.
continuous animation. The key to such animation is the idea of showing a
series of slightly different still images (or frames) in rapid succession. In our
case, we might wish to achieve a rotation of 90 by repeatedly applying a
rotation of 1 and displaying each interim image on the screen.
Simple Animation and Interaction 123
In continuous animation, the screen is constantly being refreshed (usually
at a constant rate) to keep up with a continually changing data structure.
8.2 Changing the drawing in response to user interaction
Let us begin with the simple case though - applying a simple transforma-
tion (lets use a translation by 50 units to the right) in response to some user
input and displaying the transformed drawing. An example of this, is making
this friendly frog jump for us when a key is pressed or a mouse is clicked.
Figure 60. Hopping frog - before and after hopping
In order to achieve this, we must first master 3 simple tricks - erasing, get-
ting user input and double buffering.
8.2.1 Drawing/erasing
In order to show a new or transformed version of a drawing, it is neces-
sary to first erase the old drawing and then rapidly draw the new one. The
programs we have developed so far are equipped with draw() methods in the
appropriate classes. These must now be supplemented with erase() meth-
ods.
The Line2d.erase() method is identical to the Line2d.draw() method,
except we set the drawing colour to white (the usual background colour)
before drawing any lines. Indeed, we need to add a colour setting line to
draw() to ensure that the drawing colour gets correctly set to black:
Example 35. Line2d.erase()
1 public void erase(Graphics g) {
2 g.setColor(new Color(255,255,255));
3 g.drawLine((int)src.x(), (int)src.y(), (int)dest.x(),
(int)dest.y());
Simple Animation and Interaction 124
4 }//end erase
Example 36. Line2d.draw()
1 public void draw(Graphics g){
2 g.setColor(new Color(0,0,255));
3 g.drawLine((int)src.x(), (int)src.y(), (int)dest.x(),
(int)dest.y());
4 }//end draw
The usual mechanism of passing method calls from drawings to shapes to
lines must also be implemented.
8.2.2 Getting keystrokes/mouse-events
Getting user input in Java is a subject in itself. The whole architecture of
eventListeners and event objects is beyond the scope of this book.
Instead, a simple example of getting mouse and keyboard events will suffice
for most of what we need.
We can add our user input handling code to the constructor of the Gapp
class:
Example 37. Getting/handling user input
1 addMouseListener ( new MouseAdapter() {
2 public void mousePressed(MouseEvent evt) {
3 System.out.println("Mouse!");
4 frog.transform(right);
5 repaint();
6 }
7 });
8
9 addKeyListener ( new KeyListener() {
10 public void keyTyped(KeyEvent evt) {
11 System.out.println("Key!");
12 frog.transform(right);
13 repaint();
14 }//end keyTyped
15
16 public void keyPressed(KeyEvent evt) {
17 }
18
19 public void keyReleased(KeyEvent evt) {
20 }
21 });
Simple Animation and Interaction 125
Now, when we run the program and either click the mouse or press a key,
our frog will tell us what we just did and jump to the right. The syntax of all
this is rather bizarre, we are using an unnamed inner class - check a good
Java book for details. In addition, the keyPressed() method and keyRe-
leased() methods dont do anything. This is deliberate, but they have to be
there, see the on-line Java documentation for why this is so.
Aside Such methods are generally known as event handlers
8.2.3 Double Buffering
This technique is primarily used to achieve smoothness in continuous ani-
mation (rather than the discrete hop we are about to attempt). However, when
implemented in the basic 2d framework that we are using, it has another use-
ful property: that of allowing us to move all of the application specific code
out of the Gcanvas class (which then become truly generic, in the sense that
it can be used unaltered in any program, rather like, Line2d, Point2d etc.)
and into the Gapp class which then becomes the sole repository for applica-
tion specific details.
Double buffering works by drawing all of the lines that make up a draw-
ing into an off-screen buffer and then copying that buffer in a single opera-
tion into the computers video memory. This reduces on-screen flicker
which can badly detract from the smoothness of an animation.
In particular, we must add the following data members to our Gcanvas
class:
Example 38. New data members for double buffering
1 Image bufferImage;
2 Graphics bufferGraphics;
3 Dimension d;
and the componentPaint() function must look like this.
Example 39. paintComponent() method using double buffering
1 public void paintComponent(Graphics g){
2 d = getSize();
3 bufferImage = this.createImage(d.width,d.height);
4 bufferGraphics = bufferImage.getGraphics();
5
6 //draw to buffer
Simple Animation and Interaction 126
7 myDrawing.draw(bufferGraphics);
8
9 //put buffer on screen
10 g.drawImage(bufferImage,0,0,null);
11
12 //capture current state to buffer
13 bufferImage = createImage(d.width,d.height);
14 bufferGraphics = bufferImage.getGraphics();
15 //apply erase to buffer
16 myDrawing.erase(bufferGraphics);
17 }//paintComponent
Figure 61. Double buffering - two animation cycles
8.2.4 The hopping frog example
The hopping frog example program that uses the three techniques outlined
above is similar to many of our previous examples. It uses the basic 2d class
structure and matrices to specify its one transformation.
The general recipe for our Gapp constructor is now:
Set up a drawing object,
transform data structure
draw to the buffer
perform erase
copy
bufferGraphics g
transform data structure
draw to the buffer
perform erase
copy
Simple Animation and Interaction 127
Set up a shape object
Add lines to the shape object
Add the event handlers
8.3 Continuous animation
Continuous animation like movies, television and animated cartoons is a
trick. All of these achieve the impossible feat of making a picture move
by showing in very rapid succession a whole series of slightly different still
images. A feature of the human visual system known as persistence of
vision allows us to be fooled into seeing smooth, continuous action rather
than a series of stills. The frame rate of an animation is the number of still
displayed per unit time. Television uses a frame rate of 25 frames per second
(fps), movie 24 fps whereas simple cartoon animation may use 12-15 fps.
Continuous animation is characterised by the need for the screen to be
refreshed to keep up with a constantly changing data structure. A common
way of implementing this scenario is to use multiple threads with one thread
handling the modifications to the data structure and another being responsi-
ble solely for repainting the screen. (i.e running the double buffering).
Simple Animation and Interaction 128
Figure 62. Multithreaded Double buffering - two animation cycles
A discussion of threading is again outwith the scope of this book. You are
referred to any good Java textbook. The following example should serve to
give you the basic idea.
Both Gapp and Gcanvas extend the Runnable class. Each has a thread
variable. The run() method of Gcanvas consists of an infinite loop which
repaint()s the screen (causing the paintComponent() callback to be
called) then pauses for 20ms.
Example 40. Multi-threaded Gcanvas
1 public void animateStart(){
2 thr.start();
3 }
4
5
6
transform data structure
draw to the buffer
perform erase
copy
bufferGraphics g
transform data structure
draw to the buffer
perform erase
copy
thread A
thread B
Simple Animation and Interaction 129
7 public void run() {
8 try {
9 for (;;){
10 //System.out.println("Gcanvas...");
11 repaint();
12 Thread.sleep(20);
13 }//end for
14 }// end try
15 catch (InterruptedException e) {
16 }
17 }// end run
18
19
20
21 public void animateStop() {
22 thr.stop();
23 }// end animate stop
24
The Gapp.run() method uses the same technique to repeatedly apply a
local rotation transformation to the drawing every 20ms.
Some mechanism to start the threads in response to a mouse click has also
been added.
Example 41. Multi-threaded Gapp
1 public Gapp(){
2
3 .
4 .
5 .
6 .
7 .
8
9 addMouseListener ( new MouseAdapter() {
10 public void mousePressed(MouseEvent evt) {
11 System.out.println("Mouse!");
12 myGcanvas.animateStart();
13 thr.start();
14 //repaint();
15 }
16 });
17 }// constructor
18
19
20
21
22 public void run() {
23 try {
24 for (;;){
25 //System.out.println("Gapp...");
26 myDrawing.transform(myTrans);
27 Thread.sleep(20);
Simple Animation and Interaction 130
28 }//end for
29 }// end try
30 catch (InterruptedException e) {
31 }
32 }// end run
Its a bit difficult to show animation on the printed page (thats why multi-
media was invented!) but take it from me, this apollo13 is busy going round
and round
Figure 63. Orbiting Apollo13
8.4 Animation changes in response to user interaction
There is a third possible kind of animation whereby the data structure is
constantly being changed, but the change itself changes in response to user
interaction. This is the scenario commonly found in games.
Use a switch to examine user input and set the transformation to be
applied
Example 42. Defender - a simple game
33 addKeyListener (new KeyListener() {
34 public void keyTyped(KeyEvent evt) {
35 char myChar = evt.getKeyChar();
36 System.out.println("Key Typed!" + myChar);
37 switch (myChar) {
Simple Animation and Interaction 131
38 case 'i' : myTrans=up;
39 break;
40 case 'j' : myTrans=left;
41 break;
42 case 'l' : myTrans=right;
43 break;
44 case ',' : myTrans=down;
45 break;
46 }//end switch
47 repaint();
48 }//end keyTyped
49 public void keyPressed(KeyEvent evt) {
50 }
51 public void keyReleased(KeyEvent evt) {
52 }
53 });
Simple Animation and Interaction 132
Chapter review - 8
Chapter 8 has covered the following topics
Discrete and continuous animation
Drawing and erasing
Getting user input from the mouse and keyboard in response to
events
event handling - altering transformations as a consequence
Double buffering
Multi-threaded double buffering
Simple Animation and Interaction 133
Exercises - 8
8.1 Implement the stearable spaceship game described in section
8.4.
Curves 134
Chapter 9
Curves
9.1 Introduction
All of the programs developed so far represent the world entirely as
straight lines. Whilst there are many occasions that this will suffice, a means
of representing curves lines (and eventually curved surfaces) is a vital addi-
tion to the graphics programmers toolkit.
We will look at two principal methods of curve representation Splines and
Bezier curves. By looking at the mathematical foundations behind these
techniques we will also be able to appreciate how other techniques such as
Beta-Splines and NURBS work.
The basic problem we are facing is to represent a curve easily and effi-
ciently. We could take several easy brute force and ignorance approaches:
storing a curve as many small straight line segments
- doesnt work well when scaled
- inconvenient to have to specify so many points
- need lots of points to make the curve look smooth
working out the equation that represents the curve
- difficult for complex curves
- moving an individual point requires re-calculation of the entire
curve
These are illustrated in Figure 64
Curves 135
Figure 64. Curves via brute force representation
The more points/line segments that are used, the smoother the curve.
Figure 65. More segments = smoother curves
What we want is to define a relatively small number of points and then
use a technique called interpolation to invent the extra points for us.
Curves 136
9.2 Parametric Equations
Before getting involved in curves, lets try to master interpolation and par-
ametric equations using simple straight lines first. We already know that you
can define a straight line in terms of its end points.
Figure 66. Parametric equations
Imagine walking from P
1
to P
2
at a constant speed. Let us say that we start
walking at P
0
at time t=0 and we arrive a P
1
at time t=1. Where are you at a
general time t?
dx = x
1
- x
0
dy = y
1
- y
0
x(t) = x
0
+ t.dx
y(t) = y
0
+ t.dy
In vector form:
x
0
,y
0
x
1
,y
1
dy
dx
(13,8)
(2,3)
V
1
V
0
V
diff
P
0
P
1
(7.5,4)
Curves 137
v
diff
= v
1
- v
0
v(t) = v
0
+ t. v
diff
Let us just confirm that. Where are you at t=0.5?
dx = 13 - 2 = 11
dy = 8 - 3 = 5
x(0.5) = 2 + (0.5 . 11) = 7.5
y(0.5) = 3 + (0.5 .5) = 5.5
Answer: Youll be halfway there.
We now have the equation of a straight line written as a function of some
parameter t. (It is important to note that t doesnt really signify time - thats
just the easiest way of explaining it.) Why do we use parametric equations?
Suppose we stuck to the normal way of writing the equation of a straight line
(y=mx+c) where y is expressed in terms of x. What happens when you draw
a vertical line? Try working out the gradient - (m). It is, of course, infinity
which is hard to handle on a computer. By using parametric representation,
we can avoid such problems.
9.3 Splines
One method of fitting a curve between a few points is know as the spline
curve. This idea actually has a physical analogue and was used for many
years in the shipyards to allow accurate curves to be marked out on a large
scale on the steel plates which were cut and welded to make ships hulls. In
Curves 138
that case, a flexible metal strip (a spline) was bent to the approximate shape
of the curve and heavy weights (knots) or pegs were used to force the strip to
pass through particular (measured) points.
Figure 67. Spline curve fitting
9.3.1 Representing Spline curves
To represent a straight line above, we used a linear parametric equation
(i.e. one where the highest power of t was 1). For curves, we need polyno-
mial equations. Why? Because the graphs of polynomial equations wiggle.
Figure 68. A wiggly polynomial curve
In fact, cubic equations (equations with t cubed - t
3
-in them) are what we
need. Quadratic (t
2
) lines arent wiggly enough, any higher powers are too
wiggly and require more computation.
The general form of a cubic parametric equation is:
x
t
= a
0
+ a
1
t + a
2
t
2
+ a
3
t
3
(Equation 36)
similarly for y
spline
knots
Curves 139
y
t
= b
0
+ b
1
t + b
2
t
2
+ b
3
t
3
(Equation 37)
Ok, we know the general form, we know it wiggles, how do we make it
wiggle where we want it to? Keep bearing in mind that what we want to do
with these equations is use them to generate extra points on our curve that we
will join with lots of short straight lines. Consider the following section of a
curve:
Figure 69. Two segments of a spline
Figure 69 shows two adjacent segments of an assumed smooth curve
through a set of nodes N
1
to N
m.
Each segment is represented by cubic para-
metric equations like Equation 36 and Equation 37. i.e We know the coordi-
nates of all N, we wish to deduce equations for each segment to allow us to
generate several extra points per segment.
For now, ignore the y equation, well stick to x. For each segment we have
an equation with four unknowns (a
0
-a
3
). For each segment, we need to find 4
boundary conditions which will let us find the unknowns. We can make use
of the properties of the point where the curves meet (N
i
).
Property 1 - The lines meet
At N
i,
the last x value in segment S
i
(where t=1) is equal to the first x
value in segment S
i+1
(where t=0).
Thus: (Equation 38)
At N
i
in segment
S
i
(t=1)
At N
i
in segment S
i+1

(t=0)
a
0
+a
1
+ a
2
+a
3
= a
0
N
i+1
N
i
N
i-1
S
i
S
i+1
Curves 140
where primed quantities (things with dashes - ) refer to segment S
i
and
unprimed to segment S
i+1
Property 2 - The join between the lines is continuous. The gradient of the
end of segment S
i
is the same as the gradient at the start of segment S
i+1
To find the gradient, we need to differentiate Equation 36 with respect to
t:
(Equation 39)
Again considering what happens in S
i
and S
i+1
: (Equation 40)
Property 3 - The lines meet smoothly - the 2nd derivative of Equation 36
is equal at the end of segment S
i
to that at the start of segment S
i+1
First we differentiate Equation 39 to gain the 2nd derivative
And once more considering what happens in S
i
and S
i+1
At N
i
in segment S
i
(t=1) At N
i
in segment S
i+1

(t=0)
dx
dt
------


a
1
2a
2
t 3a
3
t
2
+ + =
dx
dt
------


i
a
1
' 2a
2
' 3a
3
' + + =
= a
1
dx
dt
------


i 1 +
=
d
2
x
dt
2
-------- 2a
2
6at + =
Curves 141
: (Equation 41)
We need one more boundary condition. This can be obtained from the end
points of the line as a whole. One of three endpoint conditions is usually
specified:
Fixed gradient - give a value for dx/dt at either end of the curve.
Free end - The gradient is unconstrained - in effect the 2nd deriva-
tive is 0
Contour - The ends of the line meet, making the last point and the
first point identical. c.f a contour line on a map.
The equations mentioned in properties 1-3 occur for every segment of the
line. Taken together all of this lead to a set of simultaneous equations that can
be solved to find the values of a
0
-a
3
for each segment. The solution of simul-
taneous equations is outside the scope of this course. Look up matrix repre-
sentation of simultaneous equations and Gaussian elimination in any good
maths text book. The resulting expression can be found on line 26 of Exam-
ple 43.
Now all we need to do, is exactly the same for y and we are in a position
where we have a means of calculating x and y for any value of t.
9.3.2 Implementing Splines
It is convenient to represent splines using a spline class. The class will
need a vector to store its point objects, a count of how many points it has and
a means of adding points to the spline
9.3.2.1 Drawing the curve Actually drawing the curve requires that we split each
segment into many sub-segments, calculate their endpoints and draw straight
lines between them.
At N
i
in segment S
i
(t=1) At N
i
in segment S
i+1

(t=0)
d
2
x
dt
2
--------



i
2a
2
' 6a
3
' + = = 2a
2
d
2
x
dt
2
--------



i 1 +
=
Curves 142
9.3.2.2 Transforming a spline A spline can be transformed by simply applying the
required transformation to each of its constituent points. Remember the
spline itself has few points to be transformed, its just a matter of re-interpo-
lating between them after they have been transformed.
Example 43. The Spline2d class
1 import java.awt.*;
2 import java.util.*;
3
4 class Spline2d {
5 Vector points = new Vector();
6 int numberOfPoints =0;
7 int segments = 10;
8 float interval = (float)1/segments;
9
10
11 Spline2d(){
12 for (int i=0; i<10; i++) {
13 System.out.println(fact(i));
14 }
15 }
16
17
18 public void addPoint(float x, float y){
19 points.add(new Point2d(x,y));
20 numberOfPoints++;
21 }//end addPoint
22
23
24
25 public float interpolate(float t, float a, float b, float c) {
26 return((float) (2*(0.5-t)*(1-t)*a + 4*t*(1-t)*b + 2*t*(t-
0.5)*c));
27 }
28
29
30 public void draw(Graphics g){
31 float xdest = 0;
32 float ydest=0;
33
34 for (int section=0; section < numberOfPoints-2; sec-
tion++){
35 float ax = ((Point2d)points.get(section)).x();
36 float ay = ((Point2d)points.get(section)).y();
37
38 float bx= ((Point2d)points.get(section+1)).x();
39 float by= ((Point2d)points.get(section+1)).y();
40
41 float cx= ((Point2d)points.get(section+2)).x();
42 float cy= ((Point2d)points.get(section+2)).y();
43
44 float xsrc=ax;
Curves 143
45 float ysrc=ay;
46
47 for (float t=0; t<=1.001 ; t+= interval){
48 xdest=interpolate(t,ax,bx,cx);
49 ydest=interpolate(t,ay,by,cy);
50 g.drawLine((int)xsrc, (int)ysrc, (int)xdest,
(int)ydest);
51 xsrc=xdest;
52 ysrc=ydest;
53 }//for t
54 }//for section
55 }//end draw
56
57
58 public void transform(Transformation2d trans) {
59 for (int i=0; i < numberOfPoints; i = i+1) {
60 ((Line2d)points.get(i)).transform(trans);
61 }//end for i
62 }//end transform
63
64 }//end class Spline2d
9.3.3 Disadvantages of splines
Changing the position of a single node will require recalculation of
the entire curve
Overly restrictive to force the curve through each point.
9.4 Bezier Curves
An alternative to splines are Bezier curves. M. Bezier was a French math-
ematician who worked for the Renault motor car company. He invented his
curves to allow his firms computers to describe the shape of car bodies.
Curves 144
9.4.1 Representing Bezier curves
The basic idea behind Bezier curves is that, unlike splines, not each and
every point need actually be on the line. The points act as control points -
attracting the drawn line towards themselves. Once again a parametric repre-
sentation is used the idea being that the influence or attraction on the
curve of each point varies with t.
Figure 70. A Bezier curve
In Figure 70, at t=0, N
0
is the major (100%) influence on the line and the
others have no effect. At t=1, the situation has changed to the state where N
0
has no effect on the line, but N
3
attracts it completely. N1 and N1 are never
100% in control as that would mean the line passing through them.
Once again polynomials are used to create the curve and the influence that
each point exerts upon the curve at point t is given by a polynomial equation
(the Bezier polynomial). A 4-point curve will have 3 segments (n=3) as in
Figure 71:
Figure 71. A curve of 3 segments
N
0
N
1
N
2
N
3
N
0
N
1
N
2
N
3
Curves 145
The Bezier polynomials for a 4 point curve are:
Figure 72. The Bezier Polynomials
The equation of these curves is
:
The parametric equation actually representing the curve can be regarded
as the sum of the influences, i.e the sum of the Bezier polynomials:
(Equation 42)
(Equation 43)
i.e. B
in
(t) represents the influence of point x
i
,y
i
t=0 t=1
influence
B
03
t=0 t=1
B
13
t=0 t=1
B
23
t=0 t=1
B
33
influence
influence
influence
B
in
t ( )
n!
i! n i ( )!
--------------------- t
i
1 t ( )
n i
=
x t ( ) x
i
B
in
t ( )
i 0 =
n

=
y t ( ) y
i
B
in
t ( )
i 0 =
n

=
Curves 146
9.4.2 Implementing Bezier curves
The basics of the Bezier class are the same as the spline, a mechanism for
storing/adding the points.
9.4.2.1 Solution based on Bezier polynomials
In the drawing function, the bezier polynomials can be used directly. This
however is not a particularly efficient implementation.
Example 44. Direct evaluation the Bezier polynomials
1 import java.awt.*;
2 import java.util.*;
3
4
5 class Bezier2d {
6
7 Vector points = new Vector();
8 int numberOfPoints =0;
9 int segments = 10;
10 float interval = (float)1/segments;
11
12
13 Bezier2d(){
14 for (int i=0; i<10; i++) {
15 System.out.println(fact(i));
16 }
17 }
18
19
20
21 public void addPoint(float x, float y){
22 points.add(new Point2d(x,y));
23 numberOfPoints++;
24 }//end addLine
25
26
27
28 int fact(int x){
29 if (x == 0) {
30 return 1;
31 } else {
32 return (x * fact(x-1));
33 }
34 }//fact
35
36
37
38
39 int choice(int n, int i) {
40 return(fact(n)/((fact(i)*fact(n-i))));
Curves 147
41 }//c
42
43
44
45 float bezier(int i, int n, float t){
46 float bint = choice(n,i) * (float)Math.pow(t,i) *
(float)Math.pow((1-t),n-i);
47 System.out.println("bezing: i = " + i + ", n = " + n + ",
t= " + t + ", bint = " + bint);
48 return( bint );
49 }//bezier
50
51
52
53 public void draw(Graphics g){
54 // set colour black
55 g.setColor(new Color(0,0,0));
56 System.out.println("drawing");
57 float xsrc=((Point2d)points.get(0)).x();
58 float ysrc=((Point2d)points.get(0)).y();
59 for (float t=0; t<=1.1 ; t+= interval){
60 float xdest=0;
61 float ydest=0;
62 for (int i=0; i<numberOfPoints; i++){
63 float bint = bezier(i,numberOfPoints-1,t);
64 xdest += ((Point2d)points.get(i)).x() * bint;
65 ydest += ((Point2d)points.get(i)).y() * bint;
66 } //for i
67 g.drawLine((int)xsrc, (int)ysrc, (int)xdest,
(int)ydest);
68 xsrc=xdest;
69 ysrc=ydest;
70 }//for t
71 }//end draw
72
73
74
75
76
77
78 public void transform(Transformation2d trans) {
79 for (int i=0; i < numberOfPoints; i = i+1) {
80 ((Line2d)points.get(i)).transform(trans);
81 }//end for i
82 }//end transform
83
84
85 }//end class Bezier2d
9.4.2.2 Recursive technique A more interesting technique is the recursive means
of drawing ever closer approximations to a true Bezier curve Figure 73.
Curves 148
.
Figure 73. Recursive method of drawing Bezier curves
The algorithm can be informally described thus:
1 Start with 4 known points (a,b,c,d)
2 Calculate the midpoints (e,f,g) between those points:
3 ex = ax + (bx-ax)/2
4 and similarly for all others
5
6 Calculate the midpoints (h,i)
7 Calculate the midpoint (j)
8
9 if the length of the lines ae, eh, hj are all less than q (where q
is choosen to give a smooth curve - typically 1 < q <10) then
10 draw straight lines ae,eh,hj
11 else
12 start again using a,e,h,j as the four known starting points
13
14 if the length of the lines ji, ig, gd are all less than q then
15 draw straight lines ji, ig, gd
16 else
17 start again using j,i,g,d as the four known starting points
A Java implementation of this is given as Example 45.
Example 45. The recursive algorithm
1 import java.awt.*;
2 import java.util.*;
A
B
C
D
e
f
g
h
i
j
Curves 149
3
4
5 class Bezier2d {
6
7 Vector points = new Vector();
8 int numberOfPoints =0;
9 int segments = 10;
10 float interval = (float)1/segments;
11
12
13 Bezier2d(){
14 for (int i=0; i<10; i++) {
15 System.out.println(fact(i));
16 }
17 }
18
19
20 public void addPoint(float x, float y){
21 points.add(new Point2d(x,y));
22 numberOfPoints++;
23 }//end addLine
24
25
26
27
28 public void recDraw2(Point2d a, Point2d b, Point2d c, Point2d
d, Graphics gr){
29 Point2d e,f,g,h,i,j;
30 float ae,eh,hj,ji,ig,gd;
31
32 e = new Point2d(a.x() + (b.x()-a.x())/2, a.y() + (b.y()-a.y())/2);
33 f = new Point2d(b.x() + (c.x()-b.x())/2, b.y() + (c.y()-b.y())/2);
34 g = new Point2d(c.x() + (d.x()-c.x())/2, c.y() + (d.y()-c.y())/2);
35 h = new Point2d(e.x() + (f.x()-e.x())/2, e.y() + (f.y()-e.y())/2);
36 i = new Point2d(f.x() + (g.x()-f.x())/2, f.y() + (g.y()-f.y())/2);
37 j = new Point2d(h.x() + (i.x()-h.x())/2, h.y() + (i.y()-h.y())/2);
38
39
40 ae = (float)Math.sqrt( Math.pow(e.x()-a.x(),2) +
Math.pow(e.y()-a.y(),2) );
41 eh = (float)Math.sqrt( Math.pow(h.x()-e.x(),2) +
Math.pow(h.y()-e.y(),2) );
42 hj = (float)Math.sqrt( Math.pow(j.x()-h.x(),2) +
Math.pow(j.y()-h.y(),2) );
43 ji = (float)Math.sqrt( Math.pow(i.x()-j.x(),2) +
Math.pow(i.y()-j.y(),2) );
44 ig = (float)Math.sqrt( Math.pow(g.x()-i.x(),2) +
Math.pow(g.y()-i.y(),2) );
45 gd = (float)Math.sqrt( Math.pow(d.x()-g.x(),2) +
Math.pow(d.y()-g.y(),2) );
46
47 float l =10;
48 if ( ae>l || eh>l || hj>l || ji>l || ig>l || gd>l){
49 recDraw2(a,e,h,j,gr);
50 recDraw2(j,i,g,d,gr);
51 } else {
52 gr.drawLine((int)a.x(),(int)a.y(),(int)e.x(),(int)e.y());
53 gr.drawLine((int)e.x(),(int)e.y(),(int)h.x(),(int)h.y());
Curves 150
54 gr.drawLine((int)h.x(),(int)h.y(),(int)j.x(),(int)j.y());
55 gr.drawLine((int)j.x(),(int)j.y(),(int)i.x(),(int)i.y());
56 gr.drawLine((int)i.x(),(int)i.y(),(int)g.x(),(int)g.y());
57 gr.drawLine((int)g.x(),(int)g.y(),(int)d.x(),(int)d.y());
58 }
59 }//recDraw
60
61
62 public void draw(Graphics g) {
63 g.setColor(new Color(0,0,255));
64
recDraw2((Point2d)points.get(0),(Point2d)points.get(1),(Point2d)poi
nts.get(2),(Point2d)points.get(3),g);
65 }// recursive algorithm
66
67
68
69
70
71 public void transform(Transformation2d trans) {
72 for (int i=0; i < numberOfPoints; i = i+1) {
73 ((Line2d)points.get(i)).transform(trans);
74 }//end for i
75 }//end transform
76
77 }//end class Bezier2d
Proof of the equivalence of these techniques is most definitely left to the
reader!
9.5 Other Curves
Several other techniques exist for representing curves. Among those
which are beyond the scope of this book are:
Beta Splines - give reference
Nurbs (non-uniform, rational beta-splines)
9.6 The co-existence of multiple kinds of line
In order to allow Line2d objects, Spline2d objects and Bezier2d objects to
coexist in the same Shape2d, we can use the fact that Shape2ds vector of
lines can maintain of heterogeneous collection of objects - i.e. they can all be
in the vector at once. In order to use them, however, we need to use polymor-
phism to allow us to call a draw method without knowing the type of the
object whos draw method we are calling. By introducing a Java Interface
called GItem2d and having it implemented by Line2d, Spline2d and
Bezier2d we can achieve the desired effect.
Curves 151
An illustration of this can be seen in the online example optimised2d
example on the associated website :
http://www.cs.strath.ac.uk/~if/classes/52.359
Figure 74. A class structure for 2d graphics
Drawing2D
Shape2d Line2d Point2d
JFrame
Gapp
Gcanvas
JPanel
initComponents
thisWindowclosing
paintComponent
Transformation2d
Matrix
Bezier2d
GItem2d
1 M
1
1
1
1
1
M
1
1
1 1
Curves 152
Chapter review - 9
In this chapter you have seen:
The need to generate curves through interpolation
The use of parametric equations to represent curves
The derivation of Spline curves
A simple implementation of Spline curves
The derivation of the Bezier curves
Two methods of drawing Bezier curves
- One based upon direct evaluation of Bezier polynomials
- One based upon a recursive technique
Curves 153
Exercises - 9
9.1 Create and test a Java program to implement both means of plot-
ting Bezier curves.
9.2 Compare the curves produced by both means to ensure that they
produce identical results
9.3 Compare the relative efficiency of the two methods of generating
the curves in terms of the number of mathematical operations
that have to be performed to generate identical curves.
3D graphics 154
Chapter 10
3D graphics
10.1 Introduction
In the previous chapters we have mastered most of the techniques
required for 2d graphics. We could now write applications as diverse as map-
ping systems, video games and CASE tools. We are now ready to take a sur-
prisingly small quantum leap into 3-dimensional graphics. To me, this is the
real topic of the book. 2d applications are fine and in many cases exactly
what is required, but there is something almost magical about staring
through a computer screen into a cyberspace and seeing worlds and objects
that dont really exist.
We will consider two topics here: Firstly, how to represent 3d space in a
data structure (c.f. the basic 2d data structure) and secondly how that repre-
sentation can be displayed on our flat screens. Both of these tasks are best
described in terms of how the 2d systems can be expanded into the 3rd
(depth) dimension.
10.2 The 3D coordinate system
In two dimensions we considered only two coordinates x and y (or
breadth and height if you will). To add depth to a geometrical description we
need only add a third coordinate (z) which will signify depth. By convention
we use 3 mutually perpendicular axes, but from a mathematical point of
view, any 3 non co-planar axes would do. Any point in 3d space can thus be
represented by just those three numbers x,y & z.
3D graphics 155
Figure 75. 3d coordinate space
Figure 75 shows a representation of a cube using our new coordinate sys-
tem. Each line of the cube (a-l) can still be described by its endpoints just as
in 2d, but each point now has 3 coordinates. In terms of objects required to
describe the scene, the good news is that we can still use our drawing, shape,
line and point classes. The bad news is that they are all going to require some
(hopefully small) alterations to work in 3d.
10.3 Implementing 3d - the basic 3d class structure
10.3.1 Points
Each point must have an additional z coordinate, but since we shall con-
tinue the practise of using homogenous coordinates, each point now requires
4 numbers for complete representation.
For now, we shall stick to using the shape and drawing classes though this
will change we consider a more powerful technique in Chapter 11 Improv-
ing visual realism
x
y
z
(5,0,0)
(5,5,0)
(5,5,5)
(0,0,0)
(0,0,5)
(0,5,5)
(5,0,5)
(0,5,0)
a
b
c
d
e
f
g
h
i
j
k
l
3D graphics 156
10.3.2 3d Transformations
Since we now have an additional coordinate to cope with, out transforma-
tion matrices must also expand to cope. In fact, each transformation matrix
with require an extra row and an extra column to become 4x4 matrices.
10.3.2.1 Scaling The reason for this becomes self evident if we think about the scal-
ing transformation:
Note that the vector equation doesnt change from the 2d case:
p = S.p (EQ 44)
x
y
z
1
x'
y'
z'
1
S
x
0 0 0
0 S
y
0 0
0 0 S
z
0
0 0 0 1
x
y
z
1
=
3D graphics 157
Figure 76. 3d Scaling
10.3.2.2 Translation The maths behind the translation are again sufficiently similar
to the 2d case to warrant no further explanation
x
y
z
x'
y'
z'
1
1 0 0 T
x
0 1 0 T
y
0 0 1 T
z
0 0 0 1
x
y
z
1
=
3D graphics 158
Figure 77. 3d Translation
10.3.2.3 Rotation In 2 dimensions, rotation were defined to take place about some
stationary point - the centre of rotation. In 3d, all rotation take place about
one of the axes.
Figure 78. axes of rotation
x
y
z
x
y
z
x
y
z
x
y
z
+ve
+ve
+ve
3D graphics 159
Figure 79. Example rotation -90 around the x-axis
This means that 3 matrices are required, one to represent rotation about
each axis
+ve rotation about x
+ve rotation about y
x
y
z
=-90
x'
y'
z'
1
1 0 0 0
0 cos sin 0
0 sin cos 0
0 0 0 1
x
y
z
1
=
x'
y'
z'
1
cos 0 sin 0
0 1 0 0
sin 0 cos 0
0 0 0 1
x
y
z
1
=
3D graphics 160
+ve rotation about z
The relationship between these matrices and that introduced in 2d rotation
is again hopefully obvious - indeed the multiplication coefficients are identi-
cal and the different patterns in the matrix are of course just to ensure that
the right coordinates are multiplied. These matrices can be multiplied to pro-
duce matrices that represents combinations of rotations.
Figure 80. Rotation of a cube about x,y and z axes
x'
y'
z'
1
cos sin 0 0
sin cos 0 0
0 0 1 0
0 0 0 1
x
y
z
1
=
3D graphics 161
10.3.2.4 Local rotation Once more this is similar to the 2d situation. The basic rota-
tions are defined about the axes. It is therefore necessary to translate the
object to be rotated to the origin, perform the rotation and translate it back to
where it started from.
Figure 81. Example rotation -90 around the x-axis
10.4 Projections - Viewing 3d on a flat screen
At the time of writing, the majority of computer display systems have 2-
dimensional display devices (the screen). 3d holographic devices do exist,
but are (as yet!) confined to research labs and specialist applications. So, for
now, we have to have a way of displaying our computerised models of 3d
objects on flat screens. Fortunately the technique of projection was devel-
oped many years ago by architects and draughtsmen.
x
y
z
=-90
3D graphics 162
10.4.1 Projection - some definitions
Projection is based on the idea that the screen placed between us and the
object which exists in some space behind the screen. To draw onto that
screen, we project lines from the eye of the observer (the centre of projec-
tion) to the object we wish to represent. Where those lines intersect the
screen, we draw.
Figure 82. Projection
In Figure 82, AB is the projection of the line AB in the view volume.
If C is a finite distance from the screen, then a perspective projection
results. This used when visual realism is the goal of the system. By allowing
C to be infinite a parallel projection is obtained - this is much used in engi-
neering drawings, where parallel line in the view volume always produce
parallel lines on the screen.
Note that for this to work properly, the use has to position they head in the
right place relative to the screen. In practise, the numbers involved can be
chosen to make quality of the view relatively insensitive to minor move-
ments from the normal viewing position ok.
Aside As described above, there is only one centre of projection. Humans however
have two eyes. By producing two simultaneous projections based on two
slightly different centres of projection (about 8cm apart) and feeding them
separately to the left and right eyes, a passable imitation of 3d can be
obtained. This is the basis of VR headset goggles.
Several different projections exist, each with its own properties and uses.
We shall examine some of the common ones. Since the projection on screen
of any point in the view volume can be calculated, it is convenient to repre-
C
x
y
z
A
B
A
B
screen
z extent
x extent
y extent
view volume
centre of projection
3D graphics 163
sent that calculation as a transformation and hence as a matrix For each style
of projection the matrix is given along with an a representation of a cube in
that projection.
10.4.2 Parallel projection.
A parallel projection is one where all the lines that are parallel in 3d space
remain parallel when projected. For any point (x,y,z) the parallel projection
is to screen coordinated (xp,yp). Simply use xp=x and yp=y and quietly
ignore the z coordinate. In matrix form this is:
Figure 83. example parallel projection - cube house
1 0 0 0
0 1 0 0
0 0 0 0
0 0 0 1
x
y
z
1
xp
yp
0
1
=
3D graphics 164
10.4.3 Perspective projection
The simplest perspective projection is the orthogonal projection. In sim-
plest terms, this the projection that results when looking straight down the y-
axis.
Figure 84. Derivation of the perspective project transformation

we actually want:
p
(x,y,z)
z
x
screen
p
(xplot,yplot)
C
d
By similar triangles:

x
z d +
-----------
xp
d
------ =
xp
x
1
z
d
--- +
------------ =
yp
y
1
z
d
--- +
------------ =
1 0 0 0
0 1 0 0
0 0 0 0
0 0
1
d
--- 1
x
y
z
1
x
y
0
1
z
d
-- - +
=
x
1
z
d
--- +
------------
y
1
z
d
--- +
------------
0
1
1
z
d
-- - +



3D graphics 165
Figure 85. Example perspective projection
10.4.4 Oblique Parallel projections
A parallel projection is one where all the lines that are parallel in 3d space
remain parallel when projected. An oblique parallel projection is one where
the object in question is viewed from the side - unlike the plain parallel
projection. The z axis is drawn at some angle () to the x axis and z coordi-
nates are multiplied by some factor .
Consider the point P in Figure 86.
Figure 86. The derivation of oblique parallel projection transformations
P can be represented in 3D space - (0,0,1)
P can be represented in 2D (on screen coordinates) - (xp,yp)
P can be represented in 2D via polar coordinates - (,)
xp= cos
x
y

(xp,yp)
(0,0,1)
P
z
3D graphics 166
yp= sin
This is valid only for (0,0,1). For a general point (x,y,z) we need to multi-
ply by z and allow for x and y which represent the offset in 2d terms. Thus
generally:
xp = x + z cos
yp = y + z sin
In matrix form:
A number of standard oblique parallel projections are used in engineering
drawing. They can all be specified in terms of (,) or (,) since clearly (!)
tan = 1/
Figure 87. tan = 1/
1 0 cos 0
0 1 sin 0
0 0 0 0
0 0 0 1
x
y
z
1
xp
yp
0
1
=
x
y

z
(0,0,1)

3D graphics 167
10.4.4.1 Cavalier. In the cavalier projection the length of a line on the screen is
equal to its length in the model. This causes a distortion by over emphasising
the z-axis.
Figure 88. example cavalier projection
10.4.4.2 Cabinet. The foreshortening of the z axis is increased to provide a more
realistic view.
=1
(=45)
cavalier projection a = 0 - 360
= 0.5 (=63.4)
cabinet projection
=0 (=90)
orthogonal projection
Table 4. Principal Engineering Projections
3D graphics 168
Figure 89. example cabinet projection
10.4.4.3 Orthogonal The orthogonal projection (where =0) is just the simple paral-
lel projection we met in 10.4.2
3D graphics 169
10.4.5 Isometric Projection
The isometric projection has the property that all 3 axes are equally fore-
shortened allowing measurements along the axes to made with the same
scale.
Figure 90. Example isometric projection
The matrix representation of the isometric projection is:
60 sin 0 60 sin 0
60 cos 1 60 cos 0
0 0 0 0
0 0 0 1
3D graphics 170
10.5 Viewpoint Transformation
In addition to the perspective transformation, there is one other transfor-
mation that we may wish to apply to the data before it is displayed on the
screen. The viewpoint transformation gives the ability to move, pan, tilt and
zoom the camera through which we view our worlds. Figure 91 shows the
same scene being viewed from two different angles.
Figure 91. Looking at the world from a different angle
Moving the viewpoint by viewpoint transformation allows us to describe
the position of the camera in terms a translation of its position and a rotation
of its orientation. Figure 92 and Figure 93 show how the viewpoint can be
x
y
z
x
y
z
3D graphics 171
represented in terms of familiar transformations. A (camera or viewpoint) is
described as having six degrees of freedom i.e. we can translate it in the x,
y and z directions and we can spin it about the x,y, and z axes.
Figure 92. Moving the camera = translating the viewpoint
dx
dz
dy
x
y
z
3D graphics 172
Figure 93. Rotating the camera about its x,y and z axes
Fortunately we already have all the mathematical tools required to repre-
sent the position and the orientation of the viewpoint at our disposal in the
form of the matrices from the previous section.
In practice, we dont actually move the camera, what we do is the trans-
form the world in precisely the opposite sense to the way we would have
moved the camera. Figure 94 attempts to show that these operations are in
fact equivalent and that you end up with the same view. The reason that we
do it that way is simply that it is easier to program that way. Think of it in
terms of an idle cameraman who has the world moved instead of shifting the
camera
3D graphics 173
Figure 94. Moving the camera or moving the world
Viewpoint transformation is itself a combination of 2 separate transforma-
tions, one for the rotation, one for the translation. These two transformations
must be concatenated to produce the complete transformation. It is important
to note that the rotation represents a local rotation of the entire world about
the position of the camera and must be applied first.
10.6 Implementing 3d - the data model
We shall tackle the implementation of all of this by first changing our
existing 2d classes to implement a basic model of the 3d world. For now, we
arent going to change the basic class structure at all, no new classes, no new
relationships between the classes.
x
y
z
x
y
z
x
y
z
moving the camera
moving the world
same view
3D graphics 174
The basic principle here is that all the classes except Gapp are generic, in
the sense that they could be used in any application that needs to manipulate
graphics. What goes into Gapp is dependant upon the application under con-
strution. Gapp would look very different for a CAD tool when compared
with a game. For now, we shall continue using a Gapp that has some simple
key based controls that allow us to perform simple transformations on the
data model. Figure 95 serves as a reminder of the structure under discussion)
Figure 95. A basic 3d data structure
We can now consider the necessary changes from 2d to 3d one class at a
time:
Drawing3D
Shape3d Line3d Point3d
JFrame
Gapp
Gcanvas
JPanel
initComponents
thisWindowclosing
paintComponent
Transformation3d
Matrix
Bezier3d
GItem3d
1 M
1
1
1
1
1
M
1
1
1 1
3D graphics 175
10.6.1 The Matrix Class
Fortunately we did all the hard work here in 2d. This class doesnt change
at all.
10.6.2 Point3d
Point3d doesnt require too much work. The changes can be summarised
thus:
Add an extra (z) coordinate
change constructor, toString and accessor methods to match.
Example 46. Point3d
1 class Point3d extends Matrix {
2
3 public Point3d(float in_x, float in_y, float in_z) {
4 super(4,1,1);
5 m[0][0]=in_x;
6 m[1][0]=in_y;
7 m[2][0]=in_z;
8 }// end constructor
9
10 public String toString(){
11 return ("("+m[0][0] + "," + m[1][0] + "," + m[2][0] +
")");
12 }//toString
13
14 public float x() {
15 return (m[0][0]);
16 }
17
18 public float y() {
19 return (m[1][0]);
20 }
21
22 public float z() {
23 return (m[2][0]);
24 }
25
26 public void setx(float x){
27 m[0][0] = x;
28 }
29
30 public void sety(float y){
31 m[1][0] = y;
32 }
33
34 public void setz(float z){
35 m[2][0] = z;
3D graphics 176
36 }
37
38 }//end class Point3d
10.6.3 Gitem3d
Since each GItem3 needs to know how the viewpoint has been trans-
formed, we can define a static data member (i.e one that is shared by all
instances of the class) to hold that transformation.- the drawing transforma-
tion
Example 47. GItem3d
1 import java.awt.*;
2 public abstract class GItem3d{
3
4 static public Transformation3d drawingTransformation = new
Transformation3d();
5 public abstract void draw(Graphics g);
6 public abstract void erase(Graphics g);
7 public abstract void transform(Transformation3d trans);
8 public void setDrawingTransformation(Transformation3d in){
9 drawingTransformation = in;
10 }
11
12 }// GITEM
10.6.4 Line3d
From the point of view of the data model, line doesnt change much
either.
A constructor needs altering to allow the specification of the z
coordinate.
Eventually the draw() method must implement the algorithm for drawing
projections and for using the viewpoint transformation, but discussion of that
(and an example) is deferred to the next section.
10.6.5 Bezier3d
The Bezier curve class only needs a change to the addPoint() method to
allow the specification of the z coordinate. Like the straight line class above,
the draw method must implement the algorithm for drawing projections and
for using the viewpoint transformation, but once again, both discussion and
examples are deferred to the next section.
3D graphics 177
10.6.6 Transformation3d
The various transformation such as the rotations around the axes and the
various projection transformations can all be added here.
Example 48. Transformation3d
1 class Transformation3d extends Matrix{
2
3 Transformation3d(){
4 super(4,4,0);
5 m[0][0]=1;
6 m[1][1]=1;
7 m[2][2]=1;
8 m[3][3]=1;
9 }//constructor
10
11
12 Transformation3d(int in_rows, int in_columns, float val){
13 super(in_rows,in_columns,val);
14 }//constructor
15
16
17 Transformation3d(float[][] inData){
18 super(inData);
19 }//constructor
20
21
22 public Object clone() {
23 Transformation3d myClone = new Transformation3d(m);
24 return myClone;
25 }//clone
26
27
28 public void translate(float x, float y, float z) {
29 m[0][3]=x;
30 m[1][3]=y;
31 m[2][3]=z;
32 }//translate
33
34
35 public void scale(float sx, float sy, float sz){
36 m[0][0]=sx;
37 m[1][1]=sy;
38 m[2][2]=sz;
39 }//scale
40
41
42 public void rotatex(float angle) {
43 m[1][1] = (float)Math.cos(angle);
44 m[2][1] = -(float)Math.sin(angle);
45 m[1][2] = (float)Math.sin(angle);
46 m[2][2] = (float)Math.cos(angle);
3D graphics 178
47 }//rotate
48
49
50 public void rotatey(float angle) {
51 m[0][0] = (float)Math.cos(angle);
52 m[0][2] = (float)Math.sin(angle);
53 m[2][0] = -(float)Math.sin(angle);
54 m[2][2] = (float)Math.cos(angle);
55 }//rotate
56
57
58 public void rotatez(float angle) {
59 m[0][0] = (float)Math.cos(angle);
60 m[1][0] = -(float)Math.sin(angle);
61 m[0][1] = (float)Math.sin(angle);
62 m[1][1] = (float)Math.cos(angle);
63 }//rotate
64
65
66 public void perspective(float viewingDistance) {
67 m[2][2]=0;
68 m[3][2]=1/viewingDistance;
69 }//perspective
70
71
72 public void isometric() {
73 m[2][2]=0;
74 m[0][0]=(float)Math.sin(Math.toRadians(60));
75 m[0][1]=-(float)Math.cos(Math.toRadians(60));
76 m[2][0]=-(float)Math.sin(Math.toRadians(60));
77 m[2][1]=-(float)Math.cos(Math.toRadians(60));
78 }//isometric
79
80
81 public Transformation3d mult(Transformation3d b){
82 float sum = 0;
83 int i,j,k;
84 if (rows != b.columns) {
85 throw new IllegalArgumentException("Matrices are not
conformable.");
86 }
87 Transformation3d result = new
Transformation3d(b.rows,columns,0);
88 for (i=0; i < b.rows; i++) {
89 for (j=0; j < columns; j++){
90 sum = 0;
91 for (k=0; k<rows; k++){
92 sum = sum + b.getElement(i,k)*m[k][j];
93 }//end for k
94 result.m[i][j]=sum;
95 }//end for i
96 }//end for j
97 return result;
98 }//mult
99 }//end class Transformation3d
3D graphics 179
10.7 Implementing 3d - Drawing, Projections and Viewpoints
We are now ready to try and implement projections and viewpoint trans-
formations. Let us first take a look at what it is we are trying to achieve. Fig-
ure 96shows an array of cubes on a plane viewed from four different points
of view.
Figure 96. Screenshot - A field of cubes from various points of view.
To summarise, what we need to do is take the 3d data model that is stored
in our shapes, lines and points - and apply a series of transformations to it
before somehow plotting it on the screen. Those transformations are:
a local rotation of the model about the viewpoints x axis
a local rotation of the model about the viewpoints y axis
a local rotation of the model about the viewpoints z axis
a translation of the model in the x direction by an amount equal to
the (negative) displacement of the viewpoint from the origin in the
x direction
a translation of the model in the y direction by an amount equal to
the (negative) displacement of the viewpoint from the origin in the
y direction
a translation of the model in the z direction by an amount equal to
the (negative) displacement of the viewpoint from the origin in the
z direction
one of the projection transformations
3D graphics 180
In practise, what we do is concatenate all of those transformations into
one (known as the drawing transformation) by multiplying them in the order
that they are listed above and calculate the coordinates that result by apply-
ing the transformation to each point in the model.
The first point to note about implementing all of this is that we dont want
to change the world! The drawing transformation is never applied to the
model itself. What we actually do, is when we come to draw each line that
makes up the world (eventually each surface) is to make a temporary copy of
the points, apply the transformation to the copy and use the resulting points
as our coordinates for drawing.
Lets us consider where the constituent transformations are set up, where
they are concatenated, which objects they are shared with (i.e. which objects
can access them), where they are actually used to draw some lines and which
parts of our system may change them in order to achieve movement.
10.7.1 Setting up the drawing transformation
The setting up of the drawing transformation occurs in Gapp, basically
because the choice of a particular viewpoint and type of projection is likely
to be application dependant. Gapp actually has three transformations one is
the drawing transformation one represents the rotation of the viewpoint and
the third represents the translation of the viewpoint. This separation of trans-
formations allows independent control of the position and orientation of the
viewpoint camera.
Example 49. Transformations in Gapp
1 public class Gapp extends JFrame implements Runnable{
2
3 .
4 .
5 .
6 Transformation3d viewpointRotation = new Transformation3d();
7 Transformation3d viewpointTranslation = new Transformation3d();
8 Transformation3d viewpointTransformation = new
Transformation3d();
9 .
10 .
11 .
10.7.2 Concatenating the transformations
The rotation and translation transforms can be concatenated into one
viewpoint transformation in the Gapp class. This only needs to be done once
- or at least once every time the viewpoint changes.
3D graphics 181
10.7.3 Sharing the drawing transformation
It can be seen from the example code in section 10.6.3 above that class
Gitem3d has a static variable for holding the drawing transformation. -
essentially, each Line3d, Bezier3d or Spline3d needs to be able to access
the drawingTransformation - this is a space efficient way of doing it.
By using a method which references that static variable, we could set the
drawingTransformation by calling that method of any Line3d etc. It
makes sense to use the top level of our data structure, i.e. the drawing object
as the recipient of that method invocation. So once the concatenation has
been done, Gapp calls the setDrawingTransformation() method of the
drawing objects and thus sets the transformation to be used by the entire data
structure.
Example 50. Gapp
12 .
13 .
14 .
15 public Gapp(){
16
17 setBackground(Color.white);
18
19 // start point for camera
20 viewpointTranslation.translate(300,00,1000);
21
22 //tell the drawing what to use as its drawing transformation
23 myDrawing.setDrawingTransformation(viewpointTransformation);
24 myGcanvas.setDrawing(myDrawing);
25 .
26 .
27 .
10.7.4 Using the drawing transformation
The drawing of lines on the screen doesnt move from the 2d case - it is
still the draw methods of the line and bezier (and spline) classes that does the
actual work of line drawing.
The projection transformation is dealt with entirely within the line3d and
Bezier 3d class
3D graphics 182
Here we make copies of the endpoints of the line, apply the drawing trans-
formation to those copies (LEAVING THE ORIGINALS UNCHANGED)
and use the x and y coordinates of those points as the endpoints of the lines
we draw on screen. Note that it is a property of the projection transforma-
tions that they will always set the z coordinate to 0.
Example 51. class Line3d - data members, constructor and rawDraw()
1 class Line3d extends GItem3d implements Cloneable{
2
3 private Point3d src;
4 private Point3d dest;
5 private Matrix srcDraw = new Matrix(4,1,0);
6 private Matrix destDraw= new Matrix(4,1,0);
7
8 private Transformation3d perspective = new Transformation3d();
9 private int viewingDistance = 1000;
10 private Transformation3d isometric = new Transformation3d();
11
12
13 public Line3d (float x1, float y1, float z1, float x2, float
y2, float z2) {
14 src = new Point3d(x1,y1,z1);
15 dest = new Point3d(x2,y2,z2);
16 perspective.perspective(viewingDistance);
17 isometric.isometric();
18 }//end constructor
19
20 .
21 .
22 .
23 .
24 .
25 .
26
27 public void rawDraw(Graphics g){
28
29 srcDraw = src.mult(drawingTransformation);
30 destDraw = dest.mult(drawingTransformation);
31
32 float z1 = srcDraw.getElement(2,0);
33 float z2 = destDraw.getElement(2,0);
34
35 srcDraw = srcDraw.mult(perspective);
36 destDraw = destDraw.mult(perspective);
37
38 int x1 = (int)(srcDraw.getElement(0,0)/ (1+(z1/viewingDistance)));
39 int y1 = (int)(srcDraw.getElement(1,0)/ (1+(z1/viewingDistance)));
40 int x2 = (int)(destDraw.getElement(0,0)/ (1+(z2/viewingDistance)));
41 int y2 = (int)(destDraw.getElement(1,0)/ (1+(z2/viewingDistance)));
42
43 g.drawLine(x1, y1, x2, y2);
44
3D graphics 183
45 }//rawDraw
Example 52. Bezier3d() - data members, constructor and rawDraw()
1 class Bezier3d extends GItem3d implements Cloneable{
2 Vector points = new Vector();
3 int numberOfPoints =0;
4 int segments = 10;
5 float interval = (float)1/segments;
6
7 private Point3d src;
8 private Point3d dest;
9 private Matrix srcDraw = new Matrix(4,1,0);
10 private Matrix destDraw= new Matrix(4,1,0);
11
12 private Transformation3d perspective = new Transformation3d();
13 private int viewingDistance = 1000;
14 private Transformation3d isometric = new Transformation3d();
15
16
17 Bezier3d(){
18 isometric.isometric();
19 perspective.perspective(viewingDistance);
20 }
21
22
23 public void rawdraw(Graphics g){
24
25
26 float xsrc=((Point3d)points.get(0)).x();
27 float ysrc=((Point3d)points.get(0)).y();
28 float zsrc=((Point3d)points.get(0)).z();
29
30 for (float t=0; t<=1.001 ; t+= interval){
31 float xdest=0;
32 float ydest=0;
33 float zdest=0;
34
35 for (int i=0; i<numberOfPoints; i++){
36 float bint = bezier(i,numberOfPoints-1,t);
37 xdest += ((Point3d)points.get(i)).x() * bint;
38 ydest += ((Point3d)points.get(i)).y() * bint;
39 zdest += ((Point3d)points.get(i)).z() * bint;
40 } //for i
41
42 src=new Point3d(xsrc,ysrc,zsrc);
43 dest= new Point3d(xdest,ydest,zdest);
44 srcDraw = src.mult(drawingTransformation);
45 destDraw = dest.mult(drawingTransformation);
46
47 //use these for a perspective projection
48 srcDraw = srcDraw.mult(perspective);
49 destDraw = destDraw.mult(perspective);
50
3D graphics 184
51 //use these for isometric projection
52 //srcDraw = src.mult(isometric);
53 //destDraw = dest.mult(isometric);
54
55 g.drawLine((int)(srcDraw.getElement(0,0)/ (1+(src.z()/
viewingDistance))), (int)(srcDraw.getElement(1,0)/ (1+(src.z()/
viewingDistance))), (int)(destDraw.getElement(0,0)/ (1+(dest.z()/
viewingDistance))), (int)(destDraw.getElement(1,0)/ (1+(dest.z()/
viewingDistance))));
56
57 xsrc=xdest;
58 ysrc=ydest;
59 zsrc=zdest;
60
61 }//for t
62
63 }//end rawdraw
The action actually happens in the places where lines are drawn
Line3d.rawdraw, Bezier3d.rawdrawNote that as implemented here, the pro-
jection transformation cant be changed - were stuck with a perspective
view and the zoom factor (or viewing distance) cant be changed either. A
better implementation would allow both of these to be controlled from Gapp.
10.7.5 Changing the drawing transformation
If we wish to change the viewpoint, it is only necessary to alter the draw-
ing Transformation once (since it is a shared object). We can conveniently do
this in Gapp. The example below allows us to transform the viewpoint so
that we can walk through our model, turning in either direction to see what
is to the left and right of us. Pressing the appropriate keys, applies the appro-
priate transformation to the viewpoint transformation.
Example 53. Walk controls in Gapp - part of the KeyListener
1 addKeyListener (new KeyListener() {
2 public void keyTyped(KeyEvent evt) {
3 char myChar = evt.getKeyChar();
4 System.out.println("Key Typed!" + myChar);
5 switch (myChar) {
6 case 'i' : viewpointTranslation.transform(towards);
7 break;
8 case ' ' : viewpointTransla-
tion=(Transformation3d)identity.clone();
9 viewpointRotation=(Transformation3d)iden-
tity.clone();
10 break;
11 case 'j' : viewpointTranslation.transform(right);
12 break;
13 case 'd' : viewpointTranslation.transform(down);
3D graphics 185
14 break;
15 case 'e' : viewpointTranslation.transform(up);
16 break;
17 case 'l' : viewpointTranslation.transform(left);
18 break;
19 case ',' : viewpointTranslation.transform(away);
20 break;
21 case 's' :viewpointRotation.transform(clockwise);
22 break;
23 case 'a' : viewpointRotation.transform(anticlock-
wise);
24 break;
25 }//end switch
26
27 viewpointTransformation=viewpointTransla-
tion.mult(viewpointRotation);
28
29 myDrawing.setDrawingTransformation(viewpointTransforma-
tion);
30 repaint();
31 }//end keyTyped
32
33 public void keyPressed(KeyEvent evt) {}
34 public void keyReleased(KeyEvent evt) {}
35 });
Aside Note that there is nothing to stop an application having more than one
window each with a different viewpoint on the scene. If youve ever used the
Microsoft Flight Simulator with multiple views, youll have seen this in
action.
To tie all of the various things in this chapter together, Figure 97 shows
the class diagram of the system we have developed so far. The corresponding
java code can be found in the basic3d_with_viewpoint_transformation
example of the online examples in the associated website:
http://www.cs.strath.ac.uk/~if/classes/52359
3D graphics 186
Figure 97. Class diagram of the example
3D graphics 187
Chapter review - 10
There is a lot of material in this chapter but it can be broken down as fol-
lows
Representing the world with a 3d coordinate system
Extending the 2d data model with the extra z coordinate
Performing transformations in 3d
Projecting a 3d model onto a 2d screen
- perspective projection
- parallel projection
- isometric projection
Viewing a model from different viewpoints
Implementing all of the above
For an example of all this in action - looks at the Basic3d with viewpoint
Transformation example on the associated website.
3D graphics 188
Exercises - 10
10.1 Develop the simplest possible 3d system by extending your 2d
classes. Start by extending them to cope with z coordinates.
Implement a transformation for a cabinet projection. Use the
classes to display a wireframe drawing of a cube. Do NOT at this
stage attempt animation or viewpoint transformation.
10.2 Implement the 3d translation transformation. Use this to reposi-
tion your cube in several different places on the screen. See what
happens to the projection when you translate in the z and nega-
tive z directions.
10.3 Implement a perspective projection. Again, see what happens to
the projection when you translate in the z and negative z direc-
tions.
10.4 Implement rotation transformations for each axis.
Improving visual realism 189
Chapter 11
Improving visual realism
11.1 Introduction
Wireframe drawings of the type we have been producing so far in our con-
sideration of 3d graphics are useful for various tasks and are reasonably
cheap in terms of the processor power required to produce and manipulate
them. In terms of looking realistic (whatever that may mean), they leave
something to be desired. One problem when viewing wireframe is misinter-
preting which angle the object is being viewed from. Figure 98 shows the
problem. Is the cube being viewed from above and too the left or from below
and too the right?
Figure 98. Perspective confusion
Is this the back or
the front face of
the cube?
Improving visual realism 190
To resolve this confusion what are required are depth cues - hints to the
eye and visual perception system as to how to view the object. The best way
to do this is to depart from the wireframe representation and remove all the
lines that would not be seen from a given view point. Figure 99 illustrates
this.
Figure 99. Hidden line removal
In this chapter we will look at several techniques which can be used to
improve the realism of the objects we are creating.
11.2 Hidden line removal
There is no one best algorithm for hidden line removal (or surface culling
as it is sometime known). For a convex solid, a simple approach based upon
working out which way a surface is pointing relative to the viewer works
well.
Aside What is a convex solid? A convex solid has the property that a line drawn
from any point on one surface to a point on a second surface passes entirely
Improving visual realism 191
through the interior of the solid.
Figure 100. Convex and concave solids
In order to use this technique we must abandon our simple way of con-
structing objects purely from lines. The concept of a surface defined by a
series of points is necessary. We will come across a whole variety of different
types of surface over the next sections and chapters, but for now we will con-
sider solely flat surfaces.
Figure 101. A pair of flat surfaces defined by points
Improving visual realism 192
They can be placed into our familiar class structure as shown in Figure
102
Figure 102. 3d class structure including Surface3dWireframe
As implied above, one key requirement of our surfaces is that they are
FLAT. The easiest way to ensure this is by using only three points to define
the surface, (any polygon with only three defining points MUST be flat -
think about it) but as long as you promise not to do anything that will bend a
flat surface, we can allow them to be defined by as many points as you like.
Drawing3D
Shape3d Line3d Point3d
JFrame
Gapp
Gcanvas
JPanel
initComponents
thisWindowclosing
paintComponent
Transformation3d
Matrix
Bezier3d
GItem3d
1
M
1
1
1 1
1
M
1
1
1 1
Surface3d
M 1
Wireframe
Improving visual realism 193
How do we work out which way a surface is points? For that matter how
do we define which way a surface points, after all it has two sides? To solve
this conundrum we turn to vector mathematics. and the concept of a surfaces
normal vector. A surfaces normal vector is simply an arrow that is perpen-
dicular to that surface (i.e. it sticks straight out).
Figure 103. Some surfaces and their normal vectors
11.2.1 Determining visibility
Now consider the six faces of a cube and their normal vectors
Figure 104. normals to a cube
All we need to know is: Is the viewpoint on one side of the surface or the
other?
N
2
N
1
L
surface1
s
u
r
f
a
c
e
2
Improving visual realism 194
Vectors N
1
and N
2
are the normals to surfaces 1 and 2 respectively. Vector
L points from surface 1 to the viewpoint. It can be seen that surface 1 is visi-
ble to the viewer whilst surface 2 cannot be seen from that position. Mathe-
matically, a surface is visible from the position given by L if:
(Equation 45)
where is the angle between L and N for the surface. Equivalently:
(Equation 46)
Fortunately we can calculate cos from the direction of L (l
x,
,l
y,
,l
z
) and N
n
x
,n
y,
,n
z
). This is due to the well known result in vector mathematics - the dot
product (or the scalar product) whereby:
Aside The vertical bars denote magnitude (i.e. the length of the vector). The length
of a vector can be calculated from Pythagoras theorem:
Alternatively:
(Equation 47)
where L and N are unit vectors (i.e of length 1).
So, if L.N is a scalar (i.e. simply a number), how do we work it out?
0 90
0 cos 1
L N L N cos =
L l
x
2
l
y
2
l
z
2
+ + =
L N cos =
Improving visual realism 195
(Equation 48)
At this point, we know that we need to calculate cos , we know values
for l
x,
,l
y,
and l
z
. The only things we are missing are n
x
,n
y,
and n
z.
11.2.2 Calculating the normal vector of a surface
What we need to do is to use the other way of multiplying two vectors -
the vector product (or cross product). If you multiply any two vectors using
the vector product, the result is another vector that is perpendicular to the
plane (i.e normal) which contained the two original vectors. Figure 105
attempts to illustrate this.
Figure 105. Vector product
IMPORTANT - We need to adopt the convention that the calculated nor-
mal vector points away from the observer when the angle between the two
initial vectors is measured in an clockwise direction. Failure to do this will
lead to MAJOR confusion when you try and implement this - believe me, I
know.
L N l
x
n
x
l
y
n
y
l
z
n
z
+ + cos = =
a
b
n = a ^ b
Note:
same plane
a and b are in the
Improving visual realism 196
The only problem that then remains is where to find two vectors that we
can multiply? Answer: we can manufacture them artificially from the points
that define the plane we want the normal of.
Figure 106. Manufacturing vectors from the points of a plane.
By subtracting the coordinates of consecutive points we can form vectors
which a guaranteed to lie in the plane of the surface under consideration.
a = (a
x
,a
y
,a
z
) = (x
1
-x
0
, y
1
-y
0
, z
1
-z
0
) (Equation 49)
b = (b
x
,b
y
,b
z
) = (x
4
-x
0
, y
4
-y
0
, z
4
-z
0
) (Equation 50)
Aside Note there is nothing special about picking P
0
as the start point for the
vectors - ANY set of three points from the surface would do just as well.
We define the vectors to be anti-clockwise, when viewing the surface
from the interior (imagine the surface is part of a cube and your looking at it
from INSIDE the cube. Following the anticlockwise convention mentioned
a
b
P
0
P
1
P
2
P
3
P
4
n
(x
0
,y
0
,z
0
)
(x
1
,y
1
,z
1
)
(x
4
,y
4
,z
4
)
Improving visual realism 197
above we have produced what is known as an outward normal. An important
consequence of this is that when you define the points that define a surface in
a program, you MUST add them in anti-clockwise order.
Figure 107. Anti-clockwise order of points and the outward normal
Finally, we can work out the vector product thus:
n
x
= a
y
b
z
- a
z
b
y
(Equation 51)
n
y
= a
z
b
x
- b
z
a
x
(Equation 52)
n
z
= a
x
b
y
- a
y
b
x
(Equation 53)
These values for n
x
,n
y,
and n
z
can be fed back into equation Equation 48,
cos can be determined and we can final decide whether or not the draw the
surface. If desired, instead of merely omitting the surface altogether, it could
be drawn with a dashed line which provides an effective depth cue.
Actually, in certain cases we can simplify things a little. If the viewpoint
lies somewhere on the negative side of z-axis, as it did when we first set up
the projection transformations (i.e without any viewpoint transformations)
we can forget about L and cos . All we really need to know is whether or
not the normal points into the screen or out of it, i.e. is n
z
positive or nega-
tive? In that case, all we need to do is calculate Equation 53.
normal vector is INTO
the page
a
x
a
y
a
z
a
z
b
x
b
y
b
z
b
z
You can remember these
using this mnemonic
Improving visual realism 198
11.2.3 An alternative approach
An alternative approach is consider where the extension of the surface
cuts the z-axis - in the negative region - the surface must be tilted towards the
viewer or in the positive region, the surface must be tilted away.
Figure 108. Visibility determination by surface extension
11.3 Implementing hidden line removal
A new class Surface3dWireframe is required for this technique. It is
implemented as a Vector of lines. Most of the calculation required to deter-
mine visibility takes place in this class. The vector arithmetic however can be
implemented in one of two places. You can either define a new class
Vector3d, and implement it all in there or you can make use of the fact that a
points and vectors are more or less equivalent, and place all of the vector
maths, such as routines to find the scalar and vector products, a routine for
calculating the length of a vector and a routine for normalising a vector (i.e
reducing it to a length of 1 but keeping it pointing in the same direction) in
the Point3d class. A third possibility is to use a bit of syntactic sugar -
place all the vector routines in the Point3d class and define a Vector3d
class which inherits from Point3d but doesnt override or add to Point3d in
any way. Whatever you do, please dont confuse the JFC Vector class with
anything to do with geometrical vectors, it isnt, its just badly named.
Example 54. Point3d class with vector handling methods
1 class Point3d extends Matrix implements Cloneable{
2
3 public Point3d(float in_x, float in_y, float in_z) {
4 super(4,1,1);
5 m[0][0]=in_x;
6 m[1][0]=in_y;
7 m[2][0]=in_z;
8 }// end constructor
z
surface
extension
of surface
z=0
Improving visual realism 199
9
10 public Object clone() {
11 Point3d myClone = new Point3d(m[0][0],m[1][0],m[2][0]);
12 return myClone;
13 }// end clone
14
15
16 public float x() {
17 return (m[0][0]);
18 }
19
20
21 public float y() {
22 return (m[1][0]);
23 }
24
25
26 public float z() {
27 return (m[2][0]);
28 }
29
30
31 public void setx(float x){
32 m[0][0] = x;
33 }
34
35
36 public void sety(float y){
37 m[1][0] = y;
38 }
39
40
41 public void setz(float z){
42 m[2][0] = z;
43 }
44
45
46 public float length(){
47 return (float)Math.sqrt(Math.pow(m[0][0],2) +
Math.pow(m[1][0],2) + Math.pow(m[2][0],2));
48 }//length
49
50
51
52 public Point3d normal() {
53 Point3d result = new Point3d(0,0,0);
54 float size = length();
55 result.setx(x()/size);
56 result.sety(y()/size);
57 result.setz(z()/size);
58 return(result);
59 }//normal
60
61
62 public Point3d minus(Point3d b){
63 Point3d result = new Point3d(0,0,0);
64 result.setx( x() - b.x() );
Improving visual realism 200
65 result.sety( y() - b.y() );
66 result.setz( z() - b.z() );
67 return result;
68 }//minus
69
70
71 public Point3d plus(Point3d b){
72 Point3d result = new Point3d(0,0,0);
73 result.setx( x() + b.x() );
74 result.sety( y() + b.y() );
75 result.setz( z() + b.z() );
76 return result;
77 }//plus
78
79
80 public Point3d vec(Point3d b){
81 Point3d result = new Point3d(0,0,0);
82 result.setx( (y() * b.z() ) - (z()* b.y()) );
83 result.sety( (z() * b.x() ) - (x()* b.z()) );
84 result.setz( (x() * b.y() ) - (y()* b.x()) );
85 return result;
86 }//vector product
87
88
89 public float dot(Point3d b){
90 return((x() * b.x()) + (y() * b.y()) + (z() * b.z()));
91 }//dot product
92
93
94 public Point3d scalarMultiply(float sf){
95 Point3d result = new Point3d(0,0,0);
96 result.setx(x() * sf);
97 result.sety(y() * sf);
98 result.setz(z() * sf);
99 return result;
100 }//vector multiply this object
101
102 }//end class Point3d
The Surface3dWireframe class implements the storage and drawing of a
surface as a collection of lines. In addition, it defines a method visible()
which is used to determine whether or not a surface should be displayed. The
implementation given here makes the assumption that the viewpoint is on the
z-axis, i.e. it DOES NOT allow for viewpoint transformation.
Example 55. Surface3dWireframe
1 import java.awt.*;
2 import java.util.*;
3
4
5 class Surface3dwireframe extends GItem3d implements Cloneable{
Improving visual realism 201
6
7 int numberOfLines = 0;
8 Vector lines = new Vector();
9 Surface3dwireframe(){
10 }
11
12 public Object clone() {
13 Surface3dwireframe myClone = new Surface3dwireframe();
14 for (int i=0; i<numberOfLines; i++){
15 myClone.add-
Line((Line3d)((Line3d)lines.get(i)).clone());
16 } //for i
17 return myClone;
18 }//end clone
19
20
21 public String toString() {
22 String result = new String();
23 for (int i=0; i<numberOfLines; i++){
24 result += (Line3d)((Line3d)lines.get(i));
25 } //for i
26 return result;
27 }//end toString
28
29
30 public void addLine(Line3d inLine){
31 lines.add(inLine);
32 numberOfLines++;
33 }//end addLine
34
35
36 public void addLine(float sx, float sy, float sz, float dx,
float dy, float dz){
37 addLine(new Line3d(sx,sy,sz,dx,dy,dz));
38 }//end addLine
39
40
41 public void rawdraw(Graphics g){
42 //System.out.println("drawing");
43 for (int i=0; i<numberOfLines; i++){
44 ((Line3d)lines.get(i)).draw(g);
45 } //for i
46 }//end rawdraw
47
48
49 public void draw(Graphics g){
50 if (visible()){
51 g.setColor(Color.blue);
52 rawdraw(g);
53 }
54 }//draw
55
56
57 public void erase(Graphics g){
58 g.setColor(new Color(255,255,255));
59 rawdraw(g);
60 }//draw
Improving visual realism 202
61
62
63 public void transform(Transformation3d trans) {
64 for (int i=0; i < numberOfLines; i = i+1) {
65 ((Line3d)lines.get(i)).transform(trans);
66 }//end for i
67 }//end transform
68
69
70 public boolean visible() {
71 return(normal().z() < 0);
72 }//visible
73
74
75 public Point3d normal(){
76 // manufacture 2 vectors in the plane of the surface
77 Point3d k = ((Line3d)lines.get(1)).asVector();
78 Point3d j = ((Line3d)lines.get(0)).asVector();
79
80 //take their vector product to get the normal
81 Point3d result = j.vec(k);
82
83 //turn it into a unit vector
84 result = result.normal();
85
86 return (result);
87 }//normal
88
89
90 }//end class Surface3d
For a complete example of hidden line removal in a wireframe drawing
see the basic3d with wireframe (and hidden surface removal) example on
the associated website at:
http://www.cs.strath.ac.uk/if/classes/52.359
Improving visual realism 203
11.4 More complex shapes
The above discussion applies only to convex shapes. More complex
objects come in two forms: multiple objects and concave objects
Figure 109. More complex objects
In these cases, each surface must be considered individually. Two differ-
ent types of approach are possible:
Object space algorithms - examine each face in space to determine
it visibility
Image space algorithms - at each screen pixel position, determine
which face element is visible.
Approximately, the relative efficiency of an image space algorithm
increases with the complexity of the scene being represented, but often the
drawing can be simplified for convex objects by removing surfaces which
are invisible even for a single object.
11.4.1 The Painters algorithm
The Painters algorithm (also known as the depth sort or z-buffer algo-
rithm) is simple in principle and can be summarised thus:
Draw the objects furthest away from the viewer first, then progressively
add objects in decreasing order of distance. This approach is based upon sort-
ing the surfaces by their z-coordinates. The algorithm can be summarised
thus:
Sort the surfaces into order of increasing depth. Define the maxi-
mum z value of the surface and the z-extent.
Improving visual realism 204
resolve any depth ambiguities
draw all the surfaces starting with the largest z-value
Figure 110. Maximum z and z-extent of a surface - plan view
Ambiguities arise when the z-extents of two surfaces overlap.
Figure 111. Overlapping z-extents - plan view
z-extent
z
max
z
x
z
x
surface 1
surface 2
Improving visual realism 205
Figure 112. Depth ambiguities - front elevation
11.4.1.1 Resolving ambiguities Fortunately, an algorithm exists for ambiguity res-
olution.
Figure 113. Resolving ambiguities
Where two shapes P and Q have overlapping z-extents, perform the fol-
lowing 5 tests (in sequence of increasing complexity). If any test fails, draw
P first.
x
y
z
x
P
Q
Improving visual realism 206
x - extents overlap?.
y -extents overlap?.
Q is not completely on the side of P nearest the viewer.
P is not completely on the side of Q further from the viewer.
z
x
P
Q
no they dont, test fails
z
y
P
Q
no they dont, test fails
z
x
P
Q
yes it is, test fails
z
x
P
Q
yes it is, test fails
Improving visual realism 207
The projection of the two surfaces overlap.
If all tests are passed, then reverse P and Q in the list of surfaces sorted by
Z
max
and set a flag to say that the test has been performed once.The flag is
necessary for the case of intersecting planes. If the tests are all passed a sec-
ond time, then it is necessary to split the surfaces and repeat the algorithm on
the 4 surfaces. (end up drawing Q
2
,P
1
,P
2
,Q
1.
z
x
P
Q
y
x
P
Q
hole in P
no they dont, test fails
z
x
P
1
Q
2
P
2
Q
1
Improving visual realism 208
Chapter review - 11
This chapter has highlighted the need for depth cues and hidden line
removal to improve the visual realism of rendered scenes. This can be
achieved in several ways:
Using surfaces rather than lines/wireframe drawings
Not showing surfaces/objects which cannot be seen from the
scenes viewpoint (Hidden line/hidden surface removal).
Several approaches to determining visibility can be taken
- Calculating which way a surface is facing (surface normal)
- Base a decision on visibility on normal vector and observer
vector
- Painters (or z-buffer) algorithm
Improving visual realism 209
Exercises - 11
11.1 Write a Java program that displays a cube as a wireframe draw-
ing. Adapt the program to implement hidden line removal so that
only faces point towards the viewer are drawn.
11.2 Further adapt that program do display the faces of the cube as
areas of solid colour. You will need to draw the surfaces as filled
polygons.
11.3 Display an group of cubes with hidden surface removal (similar
to that in Figure 96). Allow the group to be rotated. Implement
the painters algorithm to ensure correct visibility.
Rendering, Shading and Colour 210
Chapter 12
Rendering, Shading and
Colour
12.1 Introduction
By introducing hidden line removal we have already taken one step away
from wireframe drawings towards being able to realistically model and dis-
play 3d objects. Perhaps the biggest step down that road comes when
attempting to colour in our simple line drawings. The various algorithms
for rendering, the process of applying lighting, colouring, shadow and tex-
ture to an object or scene in order to obtain a realistic image, are all based to
a greater or lesser extent on the study of the physical properties of light. In
this chapter we shall examine various properties of light and the way it inter-
acts with objects and develop some simple mathematical models of its
behaviour.
It is worth setting the following discussion in the context of our system as
developed so far. Currently our 3d model is made up of surfaces, each of
which we represent on the screen by drawing its outline. It we wanted to
shade each polygon (colour it in) what colour would we use? What we
basically are trying to achieve in this chapter is to derive a method for calcu-
lating that colour. Figure 114 shows the difference between a wireframe rep-
resentation and a simple rendered version.
Rendering, Shading and Colour 211
Figure 114. Wireframe representation and rendered representation
12.2 Illumination
The colour or shade that an surface appears to the human eye depends pri-
marily on three factors:
Colour and strength of incoming illumination
Colour and texture (rough/smooth) of surface
Relative positions and orientations of surface, light source and
observer
The physiological response of the eye also has a great bearing on the
appearance but that is beyond the scope of this book.
Rendering, Shading and Colour 212
12.2.1 Simplifying assumptions
12.2.1.1 Neglect colour - consider intensity For now we shall forget about colour
(well return to that later) and restrict our discussion just to the intensity of
light. We shall consider white light where the intensity of all colour compo-
nents (red, green and blue) is equal. This will give us a monochrome (black
and white) picture.
12.2.1.2 Intensity and the 1/r
2
effect Usually a light source is a mixture of diffuse
background illumination and one or more point sources of light. For the pur-
pose of this discussion (mainly to simplify the mathematics) we shall assume
that the light source we are considering is at a large distance from the scene.
This has two effects:
All light rays from the source are (virtually) parallel
There is no change in the intensity of the light across the scene -
(i.e. there is no fall off of intensity as a 1/r
2
effect.
Figure 115. Difference between close and distance light sources
Figure 115 shows the difference between close and distance illumination.
In this simple diagram, the intensity of light falling on a surface can be
thought of simply as the number of rays which hit it. It can be seen that more
rays fall on cube A than on cube B and it can quite easily be shown that the
cube A
cube B
r
a
r
b
Rendering, Shading and Colour 213
number is proportional to the reciprocal of the square of the distance between
the light source and the object. (i.e 1/r
2
where r is the distance between
source and surface).
12.2.1.3 Parallel rays It can also be seen in Figure 115 that the light rays crossing
cube B are nearly parallel whereas the rays crossing cube a are highly diver-
gent. This means for distant illumination, there is little variation in intensity
between one side of an object and the other (which means we only need to do
one calculation of intensity for the whole surface), whereas this is not true for
close illumination.
If the need exists to implement a physically accurate illumination model,
we could not make this assumption and would have to take account of these
effects, but for most purposes, the simple model will suffice.
12.2.2 Components of illumination
Consider now the light reaching the eye of an observer of a scene:
Figure 116. Basic illumination
The light reaching the eye when looking at a surface has clearly come
from a source (or sources) of illumination and bounced off the surface. In
fact the light reaching the eye can be considered as being made up of 3 dif-
ferent components:
that from diffuse illumination (incident rays come from all over
not just one direction)
that from a point source which is scattered diffusely from the sur-
face
that from a point source which is specularly reflected.
We will consider each of these components separately and them combine
them into one
surface
Rendering, Shading and Colour 214
12.2.3 Diffuse illumination
Diffuse illumination means light that comes from all directions not from
one particular source. Thinks about the light of a grey cloudy day as com-
pared to a bright sunny one: On a cloudy day, there are no shadows cast, the
light from the sun is scattered by the clouds and seems to come equally from
all directions
Figure 117. Diffuse illumination
Some proportion of the light reaching our surface is reflected back to the
observer. That proportion is dependant simply on the properties (colour) of
the surface and HAS NO DEPENDANCE on the angle of the viewer (that is
why its diffuse!).
If the strength of the incident illumination is I
d
and the observed intensity
is E
d
then the two are related by the simple formula
E
d
= R.I
d
(Equation 54)
where:
R is the reflection coefficient of the surface (0 <= R <=1) R is the
proportion of the light that is reflected back out) (Box example -
white: R=1, black: R = 0, gray: R = 0.5).
Diffuse illumination alone does not give visual realism. With no angular
dependence in the light, the observer will see no difference between a sphere
and a disc.
surface
Rendering, Shading and Colour 215
12.2.4 Diffuse scattering from a point source
When a light ray strikes a surface it is scattered diffusely (i.e. in all direc-
tions):
Figure 118. Diffuse scattering from a point source
The intensity of the reflected rays is given by:
E
sd
= R.cos(i).I
s
(Equation 55)
where:
i is the angle of incidence i.e. the angle between the surface normal
and the ray of light
0 <= i <=90 (if i > 90 the surface is invisible)
E
sd
is the intensity of the scattered diffuse rays
I
s
is the intensity of the incident light ray.
Aside Note - E
sd
doesnt change with the angle the observer is looking from. It
doesnt matter where you are looking at the surface from - thats what diffuse
means.
L
N
surface
i
Rendering, Shading and Colour 216
12.2.5 Specular reflection
The relationship between a ray of light from a point source to the reflected
ray coming from a surface is given by Lamberts law.
Figure 119. Lamberts Law
i = r (Equation 56)
- where
i is the angle of the incident ray to the normal of the reflecting sur-
face
r is the angle of the reflected ray.
For a perfect reflector, all the incident light would be reflected back out in
the direction of S. In fact, when the light strikes a surface it is scattered dif-
fusely (i.e. in all directions):
For an observer viewing as an angle (s) to the reflection direction S, some
fraction of the reflected light is still visible (due to the fact that the surface
isnt a perfect reflector - some degree of diffusion takes place). The amount
of proportion of light visible is a function of the angle s (in fact it is propor-
tional to cos (s)). It also depends on the quality of the surface and the angle
i
r
L
N
S
O
surface
L, N and S are
all in the same
plane
O not necessarily
in the same
plane
s
Rendering, Shading and Colour 217
of incidence i. We can define a coefficient w(i) - the specular reflection coef-
ficient - which is a function of the material of which the surface is made and
of i. Each surface will have its own w(i).
Figure 120. Specular reflection coefficient - w(i)
Putting all of this together gives:
E
ss
= w(i) . cos
n
(s)

. I
s
(Equation 57)
where:
E
ss
is the intensity of the light ray in the direction of O
n is a fudge factor: n=1 - rough surface (paper) n=10 smooth sur-
face (glass)
w(i) is usually never calculated - simply choose a constant (0.5?).
It is actually derived from the physical properties of the material
from which the surface is made.
0 90
glass
i
metal
w(i)
0
0.5
1
Rendering, Shading and Colour 218
Equation 57 contains the term cos
n
(s) This is in fact a fudge which has no
basis in physics, but works to produce reasonable results. By raising cos(s) to
the power n, what we do is control how much the reflected ray spreads out as
it leaves the surface.
Figure 121. Controlling the reflection - the action of n
12.2.6 Combining the illumination
Combining all three components (diffuse illumination, diffuse reflection
from a point source and specular reflection from a point source) gives us the
following expression:
E= E
d
+ E
sd
+ E
ss
(Equation 58)
or written out in full:
E = R.I
d
+ (R.cos(i) + w(i) . cos
n
(s))

. I
s
(Equation 59)
where:
E is the total intensity of light seen reflected from the surface by
the observer.
s
cos
n
(s)
0
1
n=1
n=10
i
L
N
S
surface
n=10
n=1
Rendering, Shading and Colour 219
12.2.7 Calculating E
A little more work is needed before we can use Equation 59. Let us just
examine the various terms to see what we know.
E - Were trying to calculate E, so obviously that is unknown.
R - is defined for each surface, so we need to add it as a variable to
our surface class and define it when creating the surface, so its
known.
I
d
- The incident diffuse light - we can define this to be anything
we like; 0 = darkness, for an 8-bit greyscale 255 = white. - Known
cos(i) - we can work this out from L.N - its the same calculation
we did to determine surface visibility in section 11.2.1 - Known.
w(i) - we can define this to be anything between 0 and 1 - trial and
error called for! - Known
n - is defined for each surface, so we need to add it as a variable to
our surface class and define it when creating the surface, so, basi-
cally its known.
I
s
- the incident point light source - again we can define this to be
anything we like; 0 = darkness, for an 8-bit greyscale 255 = white.
See below for a discussion of adding lights to our data model. -
Known.
cos (s) - Ah! - problem, not known. i.e. we dont know s
12.2.7.1 Calculating cos(s)
Actually, we dont try and work out s - we dont need it, what we do need
is cos(s). We rely of the same piece of maths as we did when working out
L.N - for testing surface visibility - the dot product. Recall that the angle
between any two unit vectors (A and B) is related to the vectors by A.B =
cos . We can thus see from ## that cos(s) = S.O. Work out S and O and we
will have the required cos(s).
O isnt to hard to find. Remember its the vector from the surface to the
observer. To be precise, its the vector from the centroid of the surface. We
know where the viewpoint is (from the systems viewpoint vector) and we
know where the surface is (its in our data structure), so if we calculate the
centroid, a bit of vector subtraction will give us O.
The centroid of a surface can be found by separately summing the x,y and
z coordinates of the surfaces defining points and dividing each sum by the
number of points. (effectively by finding the average of the surfaces points.):
Rendering, Shading and Colour 220
where:
N is the number of points that define the surface.
Thanks to Lamberts law we know that S is the mirror of the incident ray
about the surface normal. It can be found from some vector maths as shown
in Figure 122.
Figure 122. Finding S
S = 2Q - L (Equation 60)
Finally, we know all of the terms in Equation 59 and for any surface in our
model we can calculate the appropriate shade.
x
c
x
i
i 0 =

N
------------- =
y
c
y
i
i 0 =

N
------------- =
z
c
z
i 0 =

N
----------- =
L
N
S
Q
Q
N.cos i
i
Rendering, Shading and Colour 221
12.2.8 Implementing illumination
A program which implements this model of shading is said to implement
Lambert Shading.
To do this, we shall require another class to represent a surface:
Surface3dFlat. Its place in our class structure is given in Figure 123.
Figure 123. Graphics class structure including Surface3dFlat
Drawing3D
Shape3d
Line3d
Point3d
JFrame
Gapp
Gcanvas
JPanel
initComponents
thisWindowclosing
paintComponent
Transformation3d
Matrix
Bezier3d
GItem3d
1
M
1
1
1
1
1
M
1
1
1 1
Surface3dFlat
M
1
Surface3dWireframe
Rendering, Shading and Colour 222
It is very similar to the Surface3dWireframe of the last chapter except
that it stores it vertices as points rather than lines and that when drawing a
surface it does it by drawing a polygon that joins all of the projected points
rather than by just lines. The vital ingredient of the class is of course the fact
that is calculates the colour of that polygon as described above.
Example 56. Surface3dFlat
1 import java.awt.*;
2 import java.util.*;
3
4 class Surface3d implements GItem3d{
5
6 int numberOfPoints = 0;
7 Vector points = new Vector();
8 int segments = 10;
9 float interval = (float)1/segments;
10 boolean debug = false;
11
12 private Point3d src;
13 private Point3d dest;
14 private Matrix srcDraw = new Matrix(4,1,0);
15 private Matrix destDraw= new Matrix(4,1,0);
16
17 private Transformation3d perspective = new Transformation3d();
18 private int viewingDistance = 1000;
19 private Transformation3d isometric = new Transformation3d();
20 private Transformation3d offset = new Transformation3d();
21
22
23
24 Surface3d(){
25 isometric.isometric();
26 perspective.perspective(viewingDistance);
27 offset.translate(150,150,0);
28 }
29
30
31 public void addPoint(float x, float y, float z){
32 points.add(new Point3d(x,y,z));
33 numberOfPoints++;
34 }//end addPoint
35
36
37 public Point3d getCentroid(){
38 Point3d centroid = new Point3d(0,0,0);
39 for (int i=0; i<numberOfPoints; i++){
40 centroid.setx (centroid.x() +
((Point3d)points.get(i)).x());
41 centroid.sety (centroid.y() +
((Point3d)points.get(i)).y());
42 centroid.setz (centroid.z() +
((Point3d)points.get(i)).z());
Rendering, Shading and Colour 223
43 }//for i
44
45 centroid.setx (centroid.x()/numberOfPoints);
46 centroid.sety (centroid.y()/numberOfPoints);
47 centroid.setz (centroid.z()/numberOfPoints);
48 return(centroid);
49 }//getCentroid
50
51
52 public void rawdraw(Graphics g){
53
54 int [] x = new int [numberOfPoints];
55 int [] y = new int [numberOfPoints];
56
57 float xsrc=((Point3d)points.get(0)).x();
58 float ysrc=((Point3d)points.get(0)).y();
59 float zsrc=((Point3d)points.get(0)).z();
60
61 float xdest=0;
62 float ydest=0;
63 float zdest=0;
64
65 for (int i=0; i<numberOfPoints; i++){
66
67 xdest = ((Point3d)points.get(i % numberOf-
Points)).x();
68 ydest = ((Point3d)points.get(i % numberOf-
Points)).y();
69 zdest = ((Point3d)points.get(i % numberOf-
Points)).z();
70
71 // do projection
72 src=new Point3d(xsrc,ysrc,zsrc);
73 dest= new Point3d(xdest,ydest,zdest);
74 srcDraw = src.mult(offset);
75 destDraw = dest.mult(offset);
76 srcDraw.transform(perspective);
77 destDraw.transform(perspective);
78
79 x[i]=(int)(destDraw.getElement(0,0)/ (1+(dest.z()/
viewingDistance)));
80 y[i]=(int)(destDraw.getElement(1,0)/ (1+(dest.z()/
viewingDistance)));
81
82 xsrc=xdest;
83 ysrc=ydest;
84 zsrc=zdest;
85 } //for i
86
87 g.fillPolygon(x,y,numberOfPoints);
88 }//end rawdraw
89
90
91 public int shade(){
92 // assume one point light source and general diffuse light
93 Point3d light = new Point3d(0,0,0);
94 Point3d normal = normal();
Rendering, Shading and Colour 224
95
96 // light = vector of incident ray from point source at
point l to centroid
97
98 // light source (l) is located at (0,0,10)
99 Point3d l = new Point3d(0,0,-500);
100 light = getCentroid().minus(l);
101 // a-b = b -> a
102 light = light.normal();
103 Point3d minuslight = new Point3d(0,0,0);
104 minuslight = minuslight.minus(light);
105
106 // cosi is what we need
107 float cosi = minuslight.dot(normal());
108
109 // s = vector of reflected ray
110 // currently requires that the light sourcec
111 // be on the z axis
112 // Should be sx,sy,sz
113
114 float sx = 2 * normal.z() * normal.x();
115 float sy = 2 * normal.z() * normal.y();
116 float sz = (float) (2 * (Math.pow(normal.z(),2)));
117
118 Point3d ncosi = normal.scalarMultiply(cosi);
119 Point3d q = ncosi.plus(light);
120 Point3d q2 = q.scalarMultiply(2);
121 Point3d s = q2.minus(light);
122
123
124 s = s.normal();
125
126 // observer is the vector of the centre of projection
127
128 Point3d observer= new Point3d(0,0,-1);
129
130 // coss is what we need
131 float coss = s.dot(observer);
132
133
134 float r = 0.8f; // reflection coefficient of surface
135 float w = 0.8f; // specular reflection coeffient
136 float n = 10f; // fudge roughness of the surface
137 // n = 10 : smooth - glass
138 // n = 1 : rough - newspaper
139 float diffuse = r * cosi;
140 float reflected = w * (float) Math.pow(coss,n);
141
142 int col = 55 + (int) Math.round( (reflected) * 200);
143 return(col) ;
144 }//shade
145
146
147
148 public void draw(Graphics g){
149 if (visible()){
150 int col = shade();
Rendering, Shading and Colour 225
151 try {
152 g.setColor(new Color(col,col,0));
153 }
154 catch (Exception e) {
155 System.out.println("Surface3d.draw: calculated
colour(" + col + ") out of range");
156 g.setColor(Color.red);
157 }
158 rawdraw(g);
159 }
160 }//draw
161
162
163
164 public void erase(Graphics g){
165 g.setColor(new Color(255,255,255));
166 rawdraw(g);
167 }//erase
168
169
170
171 public void transform(Transformation3d trans) {
172 for (int i=0; i < numberOfPoints; i = i+1) {
173 ((Point3d)points.get(i)).transform(trans);
174 }//end for i
175 }//end transform
176
177
178 public boolean visible() {
179 return(normal().z() < 0);
180 }//visible
181
182
183 public Point3d normal(){
184 Point3d k =
((Point3d)points.get(2)).minus((Point3d)points.get(1));
185 Point3d j =
((Point3d)points.get(0)).minus((Point3d)points.get(1));
186
187 Point3d result = j.vec(k);
188
189 result = result.normal();
190 return (result);
191 }//normal
192
193
194 }//end class Surface3d
12.2.9 Extending to colour
As implemented above, the shading model is monochrome (greyscale,
black and white). It can (and should) be converted to full colour quite easily.
Any light source has a colour which can be expressed in terms of its red,
green and blue components.
Rendering, Shading and Colour 226
Each surface has a colour which means it reflects different colours by dif-
ferent amounts, i.e. it has a different value of R for red, blue and green
(R
r
,R
g
,R
b
). This means that to arrive at a final colour with which to shade a
surface, we must evaluate Equation 58 separately for red, green and blue
components.
E
red
= E
dr
+ E
sdr
+ E
ssr
(Equation 61)
E
green
= E
dg
+ E
sdg
+ E
ssg
(Equation 62)
E
blue
= E
db
+ E
sdb
+ E
ssb
(Equation 63)
12.3 Approximating smooth surfaces with polygon nets.
Networks of polygons are used to represent smooth surfaces. They are, of
course, only an approximation to the true surface, but they are adequate for
most computer graphics tasks. One of the commonest uses of the technique is
approximate to a cylinder by the use of a set of flat polygons:
The Lambert shading model is a great improvement over wireframe draw-
ings as far as realism is concerned. It is also a reasonably fast technique
when compared to some of the alternatives that we are about to meet. It is,
however, far from perfect. Using a different colour for each polygon means
that the polygons show up very clearly (the appearance of the model is said
to be faceted). This is fine for a cube, but not so good when attempting to use
the polygon as part of a smooth surface. Figure 124 shows 32 flat surfaces,
arranges in a circle, pretending to be a cylinder. The difference in intensity
between neighbouring sections can easily be seen.
Figure 124. Faceted appearance.
Rendering, Shading and Colour 227
The problem is made worse by a phenomena known as Mach
bands. This is a physiological effect whereby the contrast between
two areas of a different shade is enhanced as the border between
the shades. If you stare closely at the boundary of two neighbour-
ing surfaces in Figure 124, you can see that the join appears to be
slightly lighter than the surfaces.
Figure 125. Mach banding
Aside This is only a problem when the polygons concerned are part of what is
meant to be a smooth surface. There are, of course, many occasion when two
surfaces are not meant to join smoothly.
What is required is some means of smoothing the sudden transition in col-
our. Various algorithms exist for this; amongst the best known are Gouraud
shading and Phong shading - both named after their inventors.
Gouraud shading
The faceted appearance of a Lambert shaded model is due to each poly-
gon having only a single colour. To avoid this effect, it is necessary to vary
the colour across a polygon:
perceived intensity
actual intensity
Rendering, Shading and Colour 228
Figure 126. Variable shading of an individual polygon
In order to achieve this, the colour must be calculated for each pixel
instead of one colour for the entire polygon. By ensuring that the method we
use to calculate the colour results in the neighbouring pixels across the bor-
der between two polygons end up with approximately the same colours, we
will be able to blend the shades of the two polygons and avoid the sudden
discontinuity at the border.
Lambert shading is based upon calculating a single normal vector for the
surface (which is then compared to the lighting vector and the viewpoint vec-
tor to determine the colour). Gouraud shading is based upon calculating a
vertex normal rather than a surface normal. A vertex normal is an artificial
construct (a true normal cannot exist for a point such as a vertex). A vertex
normal can be thought of as the average of the normals of all the polygons
that share that vertex.
Figure 127. A vertex normal
vertex normal
surface normals
n
1
n
2
n
3
n
4
n
v
Rendering, Shading and Colour 229
n
v
can be calculated from:
(Equation 64)
- where N is the number of polygons sharing the vertex.
Having found the vertex normals for each vertex of the polygon we want
to shade,(Figure 128)
Figure 128. Find the vertex normal at each vertex
we can calculate the colour at each vertex using the same formula that we
did for Lambert Shading. Calculating the colour for all the remaining pixels
in the polygon is simply a matter of interpolating from the vertices. i.e. if your
n
v
n
i
i 1 =
N

n
i
i 1 =
N

----------------- =
Rendering, Shading and Colour 230
half-way along one of the edges, the colour value needs to be halfway
between the colour values at the ends of the edge. A value for the colour can
be given more formally by considering a scan-line through the polygon.
Figure 129. find the vertex normal at each vertex
If we stick simply to gray-scale values, the intensity of light at point P (I
p
)
can be calculated thus:
:
By performing 3 separate calculations, one for red, one for green and one
for blue, a complete colour value can be achieved.
A
B
C
P S1
S2
y
scan
I
s
1
I
c
I
c
I
a
( )
y
c
y
scan

y
c
y
a

---------------------- =
I
s
2
I
c
I
c
I
b
( )
y
c
y
scan

y
c
y
b

---------------------- =
I
P
I
s
2
I
s
2
I
s
1
( )
x
s
2
x
p

x
s
2
x
s
1

------------------ =
Rendering, Shading and Colour 231
12.4 Phong Shading
Phong shading too is based on interpolation, but instead of interpolating
the colour value, it is the normal vector which is interpolated for each point
and a colour value calculated for each pixel based on the interpolated value
of the normal vector.
The interpolation is (like Gouraud shading) based upon calculating the
vertex normals (red arrows in Figure 130), using these as the basis for inter-
polation along the polygon edges (blue arrows) and then using these as the
basis for interpolating along a scan line to produce the internal normals
(green vectors).
Figure 130. Stages of interpolation in Phong shading
Phong shading allows us to counteract the fact that we are using a flat sur-
face to approximate to a curved one.
The arrows (and thus the interpolated vectors) give an indication of the
curvature of the smooth surface which the flat polygon is approximating to.
12.4.1 Comparison of Gouraud and Phong
Phong shading is requires more calculations, but produces better results
for specular reflection than Gouraud shading in the form of more realistic
highlights.
Consider the specular reflection term in Equation 59:
cos
n
s
Rendering, Shading and Colour 232
If n is large (the surface is a good smooth reflector) and one vertex has a
very small value of s (it is reflecting the light ray in the direction of the
observer) whilst the rest of the vertices have large values of s - a highlight
occurs somewhere on our polygon.
With Gouraud shading, nowhere on the polygon can have a brighter col-
our (i.e higher value) than a vertex so unless the highlight occurs on or near a
vertex, it will be missed out altogether. When it is near a vertex, its effect is
spread over the whole polygon. With Phong shading however, an internal
point may indeed have a higher value than a vertex. and the highlight will
occur tightly focused in the (approximately) correct position.
Figure 131. Comparison of highlights with Gouraud and Phong shading.
Rendering, Shading and Colour 233
Chapter review - 12
This chapter has examined the manner in which a greater understanding
of the properties of light can lead to a more realistic approach to rendering a
scene and considered the pros and cons of various shading algorithms
Lambert shading leads to a faceted appearance
To get round this, use a smooth shading algorithm
Gouraud and Phong shading produce good effects but at the cost of
more calculations.
Gouraud interpolates the calculated vertex colours
Phong interpolates the calculated vertex normals
Phong slower but better highlights
Rendering, Shading and Colour 234
Exercises - 12
12.1 Develop a Lambert shading routine to fit into the program devel-
oped for Exercise 11.2
12.2 Add Gouraud shading
12.3 Add Phong shading.
Fine detail - Texture Mapping and Bump Mapping 235
Chapter 13
Fine detail - Texture
Mapping and Bump
Mapping
13.1 Introduction
With the use of hidden surface removal and the various rendering tech-
niques, we have reached the stage where we can construct models and scenes
that are recognisable: an observer can usually work out what it is that they
are looking at. It would be possible, with a lot of time and patience to model
even the fine detail of a scene.
Take this image of a block of wood for example. It would be possible to
model every grain every knot etc. using the techniques we have covered so
far.
Fine detail - Texture Mapping and Bump Mapping 236
Figure 132. A block of wood
Producing such models (explicit modelling) is extremely difficult and
time consuming. It is better, both from a computational efficiency point of
view and in terms of keeping the modeller sane, to cheat and use an approxi-
mation to the fine detail. Two techniques in particular offer a great increase
in realism for minimal additional programming effort: texture mapping and
bump mapping.
Fine detail - Texture Mapping and Bump Mapping 237
13.2 Texture mapping
The idea behind texture mapping is that it allows us to stick a picture
onto a surface. For instance we can easily transform this box into a wall sim-
ply by sticking a picture of some bricks onto the basic shape. As the basic
shape is transformed, so is the picture
Figure 133. Building a wall
13.2.1 Modulating the colour of the surface
We wish to determine colour on a pixel by pixel basis, rather than adopt-
ing one colour for the whole surface. When performing Phong or Gouraud
shading, we already have to calculate the colour with which to paint each
pixel. At the moment the colour is worked out from:
E
r
= R
r
.I
d
+ (R
r
.cos(i) + w(i) . cos
n
(s))

. I
s
E
g
= R
g
.I
d
+ (R
g
.cos(i) + w(i) . cos
n
(s))

. I
s
E
b
= R
b
.I
d
+ (R
b
.cos(i) + w(i) . cos
n
(s))

. I
s
(These are just the colour versions of Equation 59 - see section 12.2.6)
All we need to do is to replace the R terms in these equations (which are con-
stant for every pixel on a surface) with values retrieved from an image (often
known in these circumstances as a texture map) - which can be different for
each pixel on the surface.
Fine detail - Texture Mapping and Bump Mapping 238
13.2.2 Mapping pictures onto surfaces
What we need is a means a sticking the picture onto the surface. One pos-
sible approach would be to treat each pixel in the texture map as a point and
transform it along with the surface. In fact a much simpler process is to work
out how to deform the image so that it fits into the projected polygon that
results after all the various transformations.
There are ways and means of mapping any shape of image onto an arbi-
trary polygon, but for the sake of simplicity, we shall stick to mapping a rec-
tangular image onto a four sided polygon.
Figure 134. Mapping an image onto a polygon
Projection
Coordinates
Image coordinates
Fine detail - Texture Mapping and Bump Mapping 239
.
Figure 135. Mapping an image onto a polygon
It can be seen from Figure 134, that any pixel in coordinates space can be
mapped back to a pixel in image space. There exist numerous elegant and
sophisticated methods for doing this quickly and with a minimum of visual
distortion. We shall content ourselves with one that is easy to explain.
The coordinates of P on the texture map can be derived by considering the
ratios of the various lengths indicated:
AS
1
:AC = as
1
:ac
BS
2
:BC = bs
2
:bc
S
1
P:S
1
S
2
= s
1
p:s
1
s
2

so
S
1
x = (Cx-Ax). (s
1
x-ax/cx-ax)
S
1
y = (Cy-Ay). (s
1
y-ay/cy-ay)
and
S
2
x = (Cx-Bx). (s
2
x-bx/cx-bx)
S
2
y = (Cy-By). (s
2
y-by/cy-by)
Projection
Coordinates
Image coordinates
A B
C D
P
a
b
c
d
p
s
1
s
2
y
scan
S
1
S
2
Fine detail - Texture Mapping and Bump Mapping 240
Thus:
Px = (S
2
x-S
1
x) . (s
2
x-px/s
2
x-s
1
x)
Py = (S
2
y-S
1
y) . (s
2
y-py/s
2
y-s
1
y)
R
pred
- red reflectivity at point p is equal to the red value in the texture map
at point P
R
green
- red reflectivity at point p is equal to the red value in the texture
map at point P
R
blue
- red reflectivity at point p is equal to the red value in the texture map
at point P
13.3 Tilling
It is possible to adjust the number of times that the texture map is to fit
onto the surface:
Figure 136. tiled texture example
13.4 Bump mapping
With texture mapping, we modulated the colour of the surface of a pixel
by pixel basis. It can be seen from Equation 59 that there are other parame-
ters that we could modulate:
Fine detail - Texture Mapping and Bump Mapping 241
By creating another map (the bump map) which modulates the surface
normal vector, we can simulate the effect of a small local deformation in the
surface in other words, a bump. This allows us to roughen a surface, add
small details etc.
Figure 137. Effect of artificially altering the surface normal vector
Figure 137 shows how bump mapping achieves its effect. By artificially
altering the surface normal vector, we alter the direction of the S vector and
hence the amount of light reaching the observer.
Exactly the same algorithm for mapping an image onto the surface is used
as in texture mapping, but this time the value retrieved from the image repre-
sents a change in the i and r angles rather than colour information.
i
r
L
S
O
surface
s
modulating N
darker
lighter
Fine detail - Texture Mapping and Bump Mapping 242
13.5 Some examples of texture and bump mapping
The skilful use of this technique along with good scene lighting can pro-
duce startlingly realistic results.
Figure 138. Texture mapping, bump mapping and good lighting.
1
1. Illustrations by kind permission of W.L. Arance. See http://www.arance.net/textures.htm for some excellent examples of
the art of bump and texture mapping.
Fine detail - Texture Mapping and Bump Mapping 243
Chapter review - 13
In this chapter you will have seen:
the need to model fine details to achieve realism
that explicitly modelling fine details is difficult and time consum-
ing.
fine detail can be simulated using texture mapping and bump map-
ping
texture mapping works by modulating the surface colour term in
the shading equation
bump mapping works by modulating the surface normal vector in
the shading equation.
Fine detail - Texture Mapping and Bump Mapping 244
Exercises - 13
13.1 Using the approach of Section 13.2.2, produce a program which
can display a .gif file in an arbitrary quadrilateral.
13.2 Using your answer to either Exercise 12.2 or Exercise 12.3 as a
basis, incorporate the answer to Exercise 13.1 and implement
texture mapping.
Ray Tracing 245
Chapter 14
Ray Tracing
14.1 Introduction
The lighting, rendering and texturing techniques of the preceding chapters
are the subject of continued research and development with ever faster and
more realistic algorithms being developed. They are much used in computer
games, VR systems and other application where the rendering is performed
in real time. For the highest quality display of a scene however, we must turn
to a completely different technique for rendering: ray tracing algorithms.
These techniques allow realistic images to be produced which include
shadows, reflection and transparency but such realism is only achieved at
vast computational cost. The same underlying data model (surfaces, lines
points etc.) is till employed, but the means of converting the model into a
scene is radically different.Ray tracing is based upon the fact that a ray of
light is reversible. Instead of calculating the path of a ray of light from a
source, to a surface, through the screen and to the eye (which is effectively
what we have been doing) we reverse the light path. For each pixel in an
image, we calculate the path of a ray of light from the eye of the observer,
through the pixel in question, back into the scene bouncing off surfaces or
travelling though transparent (and semi transparent solids) and finally back
to the source of illumination. By working out all the factors that could influ-
ence the ray of light on its journey, a pixel colour can be deduced. Due to the
computational intensity of this approach it is currently usually performed
off-line with the rendered images being combined afterwards to provide
animated sequences.
Ray Tracing 246
14.2 Follow a ray
Lets us follow a ray on its reverse journey from eye to source. Each ray
ends its journey at the same known viewpoint having travelled through a sin-
gle pixel on screen (remember, this process must be repeated for each pixel).
Figure 139. Ray tracing - eye to screen to surface
When (by backtracking) we hit a surface, we must work out where the
light that goes back in the direction weve just come from could have origi-
nated. There are several possibilities, each of which may make some contri-
bution to our ray:
a specular ray (for good reflectors)
a refracted ray (for transparent materials)
an illumination ray (directly from a light source)
a diffuse ray (possibly thousands)
Ray Tracing 247
.
Figure 140. Ray tracing - at a surface
14.2.1 The Ray Tree
To determine the brightness of each pixel we must calculate all the possi-
ble sources of light that contribute to its brightness. Each time a ray encoun-
ters a surface it spawns many more (potential) rays. This construction of rays
is named a ray tree. Each pixel has it own ray tree. The final brightness of the
pixel is the sum of the spawned rays in that tree.
14.3 Types of ray
Now we must examine how to treat each of the different kinds of ray:
14.3.1 Normal Rays
A normal ray is either a reflected or a refracted ray. When a normal ray
strikes an object, if the object is an illumination source, it acquires the bright-
ness of it, otherwise it spawns a reflected ray, a refracted ray and one illumi-
nation ray to each other illumination source in the scene.
incoming
ray
illumination ray
reflected ray
illumination
ray
object
normal
refracted ray
diffuse rays
radiate out in all
directions from
the surace
Ray Tracing 248
14.3.2 Illumination Rays
When an illumination ray hits an object, if the object is an illumination
source the ray takes the value of the brightness of the source. Otherwise the
object is assumed to be dark and the ray is dropped. This is thus the mecha-
nism by which shadow arise.
14.3.3 Diffuse Rays
Diffuse rays are a special form of normal rays which are largely responsi-
ble for the interactions of surfaces with others nearby. Think about a white
sheet of paper held next to a bright coloured surface. Light diffusely scat-
tered from the coloured surface will make the paper appear to take on a tinge
of the same colour.
A large number of diffuse rays are required for realism. This represents a
major performance obstacle to the ray tracing technique.
14.3.4 Computing the brightness
As a ray from a source passes through the scene every time it interacts
with a surface it loses some brightness either through absorption or through
the light being spread over an inclined surface.
The effect is an overall loss of brightness. The loss factor, F, can equally
well be computed whilst following the ray from the viewer back to the
source.
14.3.5 Reducing Computation
Ray tracing is a computationally intensive technique, usually executed on
high performance workstations. Anything that can be done to reduce the
number of calculations will be a welcome improvement. This can be
achieved by pruning rays from the tree and following them no further.
Any ray that hits darkness can be dropped.
A ray may be traced until its brightness is known
If the loss factor gets to small, then the ray can be pruned.
As a last resort, the depth of the tree can simply be limited.
14.4 Determining Intersections
A basic requirement for any ray-tracing algorithm is the ability to detect if
and where a ray intersects a surface. The section presents, without proof or
derivation, the necessary maths to perform the detection of intersections.
Ray Tracing 249
14.4.1 Outline
Figure 141. Ray from centre of projection to first intersection with surface
The algorithm for determining whether (and where) the path of a ray
intersect a surface can be expressed in pseudocode thus:
For each pixel on screen, determine the vector equation of a
straight line from the centre of projection (see Section 10.4.1)
through the pixel and into the view volume.
for each surface in the model,
find the equation of the plane containing the surface
find whether or not line and the plane intersect
If they do,
find the point of intersection
Find whether the surface contains the point
It can be seen straight away that this will take a lot of computational effort
if each surface in the model has to be examined for each pixel in the image.
C
A
B
screen
z extent
x extent
y extent
view volume
centre of projection
ray
p
l
a
n
e

o
f

s
u
r
f
a
c
e
s
u
r
f
a
c
e
Ray Tracing 250
14.4.2 Find the equation representing the light ray
A ray may be considered using a parametric representation of a vector
(not a Java Vector) - Figure 142:
Figure 142. Light rays - parametric vector representation
Any point (x,y,z) on the extension of a straight line passing through
(x
0
,y
0
,z
0
) and (x
1
,y
1
,z
1
) can be described thus:
x = x
0
+ t (x
1
- x
0
) (Equation 65)
y = y
0
+ t (y
1
- y
0
) (Equation 66)
z = z
0
+ t (z
1
- z
0
) (Equation 67)
You might like to think of that as meaning move from the origin to the
point (x
0
,y
0
,z
0
) and then move t times the length of v in the direction of v and
youll be at point (x,y,z).
For the sake of being concise we can define:
x = x
1
- x
0
(Equation 68)
y = y
1
- y
0
(Equation 69)
z = z
1
- z
0
(Equation 70)
then
x = x
0
+ t x (Equation 71)
y = y
0
+ t y (Equation 72)
z = z
0
+ t z (Equation 73)
(x
0
,y
0
,z
0
)
(x
1
,y
1
,z
1
)
(x,y,z)
v
Ray Tracing 251
14.4.3 Intersection of straight line with a plane
Now that we have a convenient means of representing a straight line in 3
dimensions and hence the light ray, let us turn our attention to surfaces.
Recall that the equation of any (flat) surface is:
Ax + By + Cz + D = 0 (Equation 74)
Substitution and re-arrangement reveal that for any straight line and any
surface:
(Equation 75)
The only case in which a plane and a line will not intersect is when they
are parallel. In that circumstance the denominator (bottom) of Equation 75
will be 0.
14.4.4 Determining where a straight line intersects a plane
The point of intersection between a line and a plane can be determined by
substituting the value of t obtained from Equation 75 back into Equation 71 -
Equation 73
14.4.5 Determining whether that point is with a given polygon
Determining whether that point is within a given polygon is more com-
plex. The approach is to simplify the problem by dropping to 2d instead of
3d. This can be achieved by projecting the polygon onto one of the three
planes of the coordinate system. Use the one with the largest corresponding
t
Ax
0
By
0
Cy
0
D + + +
Ax By Cz + +
--------------------------------------------------- =
Ray Tracing 252
coefficient in the plane equation. The projection is achieved by simply ignor-
ing on of the dimensions. In Figure 143, the y coordinates are ignored to
project the surface onto the x-z plane
Figure 143. Projecting to 2D
The containment of the point can then be solved in 2D. To test whether or
not a point is contained in an arbitrary 2D polygon is still not that simple:
Figure 144. Points and polygons - Inside or outside?
The approach taken is to start at the point being tested, draw a line to
infinity and count how many times that line intersects with lines forming the
boundary of the polygon. It can be seem from Figure 144 that when the line
crosses a boundary an odd number of times, the point must be inside the pol-
ygon, if the crossing count is even, then the point must be outside.
H
J
K
L
H
J
K
L
x
y
z
to infinity
(and beyond!)
Ray Tracing 253
14.4.6 Applying to ray tracing
Having determined whether or not a given ray intersect a given surface,
the rules outlined in previous sections are used to determine what action to
take.
Where a ray does intersect a surface, it will be necessary to recursively
trace onward any spawned reflected and refracted rays. To determine their
direction, the same techniques used in determining reflections for shading
algorithms can be employed - see Section 12.2.7 for details
Ray Tracing 254
Chapter review - 14
In this chapter you should have learned:
What ray tracing is and why it is a useful technique
The fundamentals of the technique including:
- the different types of ray: reflected, refracted, diffuse, etc.
- the spawning of further rays when a ray encounters a surface
leading to a ray tree
- that the properties of a light ray are affected by the surfaces it
encounters
- that sources of illumination are the eventual destination of
reverse traced rays
How to trace the path of a ray and the calculation of intersections
between ray and surface.
Ray Tracing 255
Exercises - 14
14.1 Set up the code necessary to calculate the intersection between a
ray (represented as either a Line3d or a Vector3d) and a Surface.
14.2 Implement a simple ray tracer in which each ray is traced back
only as far as the first surface it encounters.
14.3 Enhance this to spawn the other rays as described in the chapter.
Fractals 256
Chapter 15
Fractals
15.1 Introduction
Fractal geometry is based upon the idea of self similarity - simple pat-
terns that repeat themselves on smaller and smaller scales to produce com-
plex patterns. The reasons they are of interest to computer graphics
developers are two fold:
Many patterns that occur in nature seem to be fractal
The mathematical description of fractals allows very complex pat-
terns to be described very succinctly
This means that fractal techniques offer a very efficient way of generating
realistic natural looking textures and objects in computer rendered scenes.
Clouds, coastlines, mountain and trees have all been successfully synthe-
sized using fractals.
15.2 Self similarity
The ideas of self similarity are best illustrated by first looking at some
two-dimensional examples. We can then look at how these are easily
extended to the 3d case.
In general, any fractal starts with a base shape and is then modified by
repeated recursive application of a generator rule. We illustrate this by refer-
ence to the Koch curve:
Fractals 257
15.2.1 The Koch Curve
The Koch curve is a geometrical pattern that is generated by the recursive
application of a simple rule:
Start with a base shape - in this case a simple straight line
Figure 145. Koch curve - base shape
Apply the following rule: Take the central third of the line and replace it
with a triangle.
Figure 146. Koch curve - first application of generator
Now apply this to all of the segments of the resulting line.
Figure 147. Koch curve - second application of generator
Fractals 258
After many repeated application of the rule, an artificial coastline is
produced. One interesting property of the Koch curve, but common to many
fractal patterns, is that the length of the line would ultimately become infi-
nite.
Figure 148. Koch curve -many applications
The paintComponent() method of the Gcanvas class that generates the
Koch curve is shown in Example 57
Example 57. Generating the Koch curve
1 public void koch (Point2d a, Point2d b, Graphics graf){
2
3 Point2d a2b = b.minus(a);
4 Point2d c = a.plus(a2b.scalarMultiply(.333333f));
5 Point2d e = a.plus(a2b.scalarMultiply(.666666f));
6
7 Point2d h = c.vec(e);
8
9
10 Point2d d = c.plus(h.scalarMulti-
ply(.707f)).plus(e.minus(c).scalarMultiply(0.5f));
11
12 System.out.println("h: " + h + " d: " + d);
13
14 if (h.length()<1) {
15 graf.drawLine(Math.round(a.x), Math.round(a.y),
Math.round(c.x), Math.round(c.y));
16 //graf.setColor(Color.red);
17 graf.drawLine(Math.round(c.x), Math.round(c.y),
Math.round(d.x), Math.round(d.y));
18 //graf.setColor(Color.blue);
Fractals 259
19 graf.drawLine(Math.round(d.x), Math.round(d.y),
Math.round(e.x), Math.round(e.y));
20 //graf.setColor(Color.black);
21 graf.drawLine(Math.round(e.x), Math.round(e.y),
Math.round(b.x), Math.round(b.y));
22 } else {
23 koch(a,c,graf);
24 koch(c,d,graf);
25 koch(d,e,graf);
26 koch(e,b,graf);
27 }
28 }//koch
29
30
31
32 public void paintComponent(Graphics g){
33
34 Dimension d;
35 d=getSize();
36 koch(new Point2d(0,100),new Point2d(d.width,100),g);
37 }//paintComponent
15.2.2 The Sierpinski Gasket
A second example of the use of base shapes and generator rules is the
Sierpinski Gasket: Start with a shaded triangle as the base shape and repeat-
edly remove the middle of the remaining triangle.
Figure 149. The Sierpinski Gasket
Fractals 260
Example 58. Generating the Sierpinski Gasket
1 //----------------------------------------------------------------
2 //
3 //
4 // File : Gcanvas.java
5 //
6 //
7 //----------------------------------------------------------------
8
9
10
11 import java.awt.*;
12 import javax.swing.*;
13
14 class Gcanvas extends JPanel {
15
16
17
18
19 Point2d start;
20 Point2d end;
21
22
23
24
25 public void sierpinski (Point2d a, Point2d b, Point2d c, Graphics
graf){
26
27
28 int [] x = new int [3];
29 int [] y = new int [3];
30
31 Point2d d = a.plus(b.minus(a).scalarMultiply(.5f));
32 Point2d e = b.plus(c.minus(b).scalarMultiply(.5f));
33 Point2d f = a.plus(c.minus(a).scalarMultiply(.5f));
34
35
36 x[0]=Math.round(a.x);
37 y[0]=Math.round(a.y);
38
39 x[1]=Math.round(b.x);
40 y[1]=Math.round(b.y);
41
42 x[2]=Math.round(c.x);
43 y[2]=Math.round(c.y);
44
45 graf.setColor(Color.blue);
46 graf.fillPolygon(x,y,3);
47
48
49
Fractals 261
50
51 x[0]=Math.round(d.x);
52 y[0]=Math.round(d.y);
53
54 x[1]=Math.round(e.x);
55 y[1]=Math.round(e.y);
56
57 x[2]=Math.round(f.x);
58 y[2]=Math.round(f.y);
59
60 graf.setColor(Color.white);
61 graf.fillPolygon(x,y,3);
62
63
64 if (a.minus(b).length()>20) {
65 sierpinski(a,d,f,graf);
66 sierpinski(f,e,c,graf);
67 sierpinski(d,e,b,graf);
68 }
69 }//sierpinski
70
71
72
73 public void paintComponent(Graphics g){
74
75 Dimension d;
76 d=getSize();
77 sierpinski(new Point2d(0,d.height), new Point2d(d.width/
2,0), new Point2d(d.width,d.height), g);
78 }//paintComponent
79
80
81 }//Gcanvas
82
Fractals 262
15.3 The Mandelbrot Set
A more complex and more famous example of fractal geometry is the
Mandelbrot Set - a segment of which forms the cover illustration of this
book.
Figure 150. The Mandelbrot set
This bizarre mathematical object is based upon a mathematical relation-
ship
(Equation 76)
where z and c are both complex numbers. i.e. assign z the value z2 + c
Each pixel in the image represents a point in the imaginary plane. The
value (i.e colour) of each pixel in turn is then calculated as follows. Let c
represent that point e.g. if the coordinates of the point are (1,2) then let c = 1
+ 2i.
Let z =0 + 0i
z z
2
c +
Fractals 263
Count the number of times that Equation 76 can be applied before the
value of z begins to diverge - i.e. before either the real or imaginary part
grows > (say) 2. Assign a colour to the pixel depending on that count. The
code in Example 59 makes the algorithm clear.
Example 59. Calculating the mandelbrot set
1 class Complex {
2
3
4 public float r = 0;
5 public float i = 0;
6
7
8
9 Complex (){
10 }//constructor
11
12
13
14 Complex (float real, float imaginary){
15 r=real;
16 i=imaginary;
17 }//constructor
18
19
20 public Complex add(Complex in){
21 Complex result = new Complex();
22 result.r = r + in.r;
23 result.i = i + in.i;
24 return result;
25 }//add
26
27
28
29
30 public Complex mult(Complex in){
31 Complex result = new Complex();
32 result.r = (r * in.r) - (i * in.i);
33 result.i = (i * in.r) + (r * in.i);
34 return result;
35 }//add
36
37
38 public float mod(){
39 return (float)(Math.sqrt((r*r) + (i*i)));
40 }
41
42 }// complex
1 import java.awt.*;
2 import javax.swing.*;
Fractals 264
3 //----------------------------------------------------------------
4 //
5 //
6 // File : Gcanvas.java
7 //
8 //
9 //----------------------------------------------------------------
10
11
12 class Gcanvas extends JPanel {
13
14
15 float sf=0.01f;
16 float x_offset= -2.5f;
17 float y_offset= -2;
18 Dimension d;
19
20
21
22 public int mandel(Complex in ){
23 Complex orig = in;
24 int i;
25
26 for (i=0; i<200; i++) {
27 in = in.mult(in).add(orig);
28 if (in.mod() > 2) {
29 break;
30 }
31 }// for i
32 return(i);
33 }
34
35
36
37
38
39 public Color mandel2shade(int in) {
40 int red = (in*1) % 255;
41 int green = (in*1) % 255;
42 int blue = (in*1) % 255;
43 Color result = new Color(red,green,blue);
44 return result;
45 };
46
47
48
49 public void paintComponent(Graphics g){
50 int x,y;
51
52 d = getSize();
53
54 for (x=0; x<d.width; x++) {
55 for (y=0; y<d.height; y++) {
56 Color shade = mandel2shade(mandel(new Com-
plex((x*sf)+x_offset,(y*sf)+ y_offset)));
57 g.setColor(shade);
58 g.drawLine(x,y,x,y);
Fractals 265
59 }// for y
60 }//for x
61
62 }//paintComponent
63
64
65 }//end of -- Gcanvas ----------------------------------------------
1
2 //----------------------------------------------------------------
3 //
4 //
5 // File : Gapp.java
6 //
7 //
8 //----------------------------------------------------------------
9
10
11 import java.awt.*;
12 import java.awt.event.*;
13 import javax.swing.*;
14
15
16 public class Gapp extends JFrame {
17
18
19
20
21
22 public Gapp(){
23 setBackground(Color.white);
24 }// constructor
25
26
27
28
29
30 public void initComponents() throws Exception {
31
32 setLocation(new java.awt.Point(0, 30));
33 setSize(new java.awt.Dimension(400, 400));
34 setTitle("Graphics Application");
35
36 getContentPane().add(new Gcanvas());
37
38
39 addWindowListener(new java.awt.event.WindowAdapter() {
40 public void windowClosing(java.awt.event.Window-
Event e) {
41 thisWindowClosing(e);
42 }
43 });
44
Fractals 266
45 }//end - initComponents
46
47
48
49
50
51
52 void thisWindowClosing(java.awt.event.WindowEvent e){
53 // Close the window when the close box is clicked
54 setVisible(false);
55 dispose();
56 System.exit(0);
57 }//end - thisWindowClosing
58
59
60
61
62
63 static public void main(String[] args) {
64 // Main entry point
65 try {
66 Gapp myGapp = new Gapp();
67 myGapp.initComponents();
68 myGapp.setVisible(true);
69 }
70 catch (Exception e) {
71 e.printStackTrace();
72 }
73 }//end main
74
75
76
77
78 }//end of class -- Gapp -------------------------------------------
Utilising fractal geometry
Whilst the above examples are good introductions to the world of fractal,
their use in generating realistic natural objects is limited. The following
three sections however show how the same techniques can be used to gener-
ate synthetic versions of natural objects (although well stick to 2d for clar-
ity): mountains and trees.
15.3.1 Mountains
Once again we shall use a base shape and a generator rule to create a pro-
file of a mountain range. The base shape shall be a straight line (as in the
Koch curve example) and the generator rule can be expressed thus: Deflect
the mid-point of the line up or down by a random amount limited by a cur-
Fractals 267
rent scale. Various effect can be obtained by changing the manner in which
the scale varies as construction proceeds. If successive generation of the pro-
file are overlaid, the evolution of the mountain range can be seen
Figure 151. Cyber-tectonics - grow your own mountain range
In the following implementation (Example 60), the limiting scale is made
to vary with a power of the depth of recursion. If that power (known as the
Jag index) is varied, different styles of profile result - Figure 152.
Example 60. Fractal mountain profile generator
1 public void mountain (Point2d a, Point2d b, float scale, Graphics
graf){
2
3 Dimension d;
4 d=getSize();
5
6
7 float ratio, jagIndex;
8
9 // jagIndex=1 normal jaggedness
10 // jagIndex<1 - very jaggy
11 // jagIndex>1 smoother
12
13
14 jagIndex=1.5f;
15 ratio = 2-jagIndex;
16
17 Point2d c = new Point2d(a.x + ((b.x-a.x)/2),(float)(((a.y+b.y)/
2) + (Math.random()-0.5)*scale));
18
19
20
21 if (b.x-a.x>5) {
1st generation
2nd generation
3rd generation
Fractals 268
22 mountain(a,c, scale*ratio, graf);
23 mountain(c,b, scale*ratio, graf);
24 } else {
25 graf.setColor(Color.blue);
26 graf.drawLine(Math.round(a.x),Math.round(a.y),
Math.round(c.x),Math.round(c.y));
27 graf.drawLine(Math.round(c.x),Math.round(c.y),
Math.round(b.x),Math.round(b.y));
28 }
29 }//mountain
30
31
Figure 152. Examples of fractal mountain profiles
Several generations are required to produce realistic results, but a limit to
the number of generations is needed in order to stop the algorithm. That limit
is sensibly reached when the limit of deflection is of the order of one pixel.
15.3.2 Trees etc.
Trees share a common fractal structure - a trunk which subdivides in
branches which sub-divide into more branches which......
Jag index = 1.2
Jag index= 1.5
Jag index = 1.8
Fractals 269
Once again, our base shape is a straight line. The generator rule is some-
thing like, take the top x% of the line and split it into n branches, degrees
between each branch. Figure 153 elucidates.
Figure 153. Generations of a fractal tree
The algorithm can be made more complex in several ways:
By varying those parameters, different styles of tree can be
obtained.
By allowing those parameters to vary randomly within limits over
the generations some realistic branching patterns can be obtained.

n=2
x=60%
Fractals 270
By varying the limits over generations some really quite convinc-
ing trees can be generated
Figure 154. Artificial trees
Fractals 271
Of course by pushing some of these variables beyond sensible limits,
some extremely unrealistic results can also be obtained.
Figure 155. Teenage mutant ninja spruce
15.4 Fractals and 3D
All of the examples of fractals have been given in 2d versions so as not to
obscure the functioning of the underlying generating mechanism with the
machinery of 3D graphics. The basic approach in using fractal techniques
in 3D is to generate the objects in the scene using the appropriate fractal
techniques and then render the scene using any of the previously covered
techniques.
Fractals 272
Chapter review - 15
In this chapter, we have covered:
the basis of fractal geometry and the principle of self similarity
The use of a base shape and generator rule to create self-similar
patterns
The occurrence in nature of fractal patterns
The utilisation of fractals to simulate naturally occurring objects.
Fractals 273
Exercises - 15
15.1 Develop a fractal tree generator.
15.2 Build a 3D fractal landscape generator. Base it upon a mesh and
deform the points of the mesh up and down according to some
rule.
Closing Remarks 274
Chapter 16
Closing Remarks
In this book I have tried to present computer graphics from the bottom up.
If the bottom is pixels and memory mapping then I certainly cant reached
the top in15 chapters. There are many further topics in CG, but armed with
the knowledge in this book, the reader should be able to pick their way
through the maze of alternative algorithms and more advanced techniques.
Research and development in computer graphics remains as strong as ever,
partly driven by the computer games fraternity seeking ever more speed and
realism, partly by the academic world with its conferences (SIGGRAPH),
journals and other academic paraphernalia and partly by the big budget
movie industry.
Remember that the examples given in the book are only one way to imple-
ment the underlying algorithms. In many cases, I have deliberately avoided
the most efficient way of doing something in order to make clear the under-
lying concepts. Indeed, it can be argued that Java isnt the most sensible lan-
guage in which to implement a graphics system, yet given the widespread
use of Java as teaching language there is a clear advantage to continuing to
use the same vehicle to get convey the concepts of CG.
As a final piece of advice I would suggest that no-one (myself included)
really understand a concept or a technique in CG without having tried to
implement it. None of it is as hard as it first looks. Have a go. Impress your-
self.
Appendices 275
Appendices
Vector and Matrix algebra 276
Appendix A
Vector and Matrix algebra
A.1 Introduction
Computer graphics is concerned with displaying images of 'objects'. The
'objects' are represented in the computer as sets of points lines and attributes
(e.g. colour, texture etc.). To display images or views of the objects requires
the points and lines to be manipulated by rotation, translation, scaling and
projection. These are all geometrical transformations, which are most con-
veniently represented using vector and matrix algebra.
For computer graphics, only a very limited amount of mathematics is
essential and it is all contained in this introduction. The emphasis here is on
simple explanation and demonstration and no attempt is made to give a seri-
ous mathematical introduction. In other words this is a 'get you by' guide to
the required mathematics and if you want to take any of the topics further
consult one of the books listed in Appendix B - Bibliography .
A.2 Co-ordinates and Vectors
The most convenient way to represent the position of a point in space is in
terms of its perpendicular distance from three axes set at right angles to each
other. Fig.1 shows the point P with co-ordinate values x=2, y=4 and z=3.
Vector and Matrix algebra 277
If you imagine that the X and Y
axes are in the horizontal plane
then the positive Z direction is
vertically upwards. This is
known as a right handed co-ordi-
nate system. In all but one case
points and lines in computer
graphics are represented in a
right handed co-ordinate system.
A left handed co-ordinate system
would have the Z axis pointed
vertically down. The co-ordinates
of the point P are normally writ-
ten (2,4,3) or in general (x,y,z).
A vector is a line with a specific direction in space. We can regard the
point P as the head of a vector from the origin O. In this case the vector p is
also written as
p = (2,4,3)
The values 2,4 and 3 are the components of the vector. It is usual to repre-
sent vectors with bold type in texts or as underline letters in hand-written
work. A line has a length, which is easily seen from Pythagoras's theorem to
be given by :
The direction of the vector in space is usually expressed in terms by the
cosines (direction cosines) of the three angles it makes with the X,Y and Z
axes.

A special vector, which we often need to refer to, is the unit vector whose
length is equal to one. The components of the unit vector are simply the
direction cosines. Unit vectors along the three axes have a special signifi-
cance and are usually designated i (X) j (Y) and k (Z). Two vectors p and q
can be added to produce a third vector s by simply adding the components:
x
y
z
4
2
3
Figure A1. right hand coordinate
system
P
P l
x
2
l
y
2
l
z
2
+ + =

x
cos
x
P
------ =
y
cos
y
P
------ =
x
cos
z
P
------ =
Vector and Matrix algebra 278
Graphically the sum is illus-
trated by 'completing the trian-
gle' as shown in Fig.2.
Subtraction of vectors is defined
in an exactly analogous way.
Multiplication is a little more
complicated because there are
three type of vector multiplica-
tion. All three will be required
in the course. The simplest form
is:
A.2.1 Scalar multiplication:
Each component of the vector p is multiplied by the same constant scalar
(real number) value . The effect of this is to keep the direction of the vector
constant but to change its length by
Scalar multiplication is use-
ful in expressing the equation of
a straight line in vector form. If
r is a vector from the origin to
any point on the line and u is a
unit vector along the line then
any point q on the line can be
written:
Q = r + u
Figure 3 shows an example
for which = 3. This is one
form of a parametric equation of
a straight line with parameter . In this context all this means is that all
points of the straight line can be reached by variation in the value of the
parameter .
A.2.2 The Scalar product of two vectors :
Two vectors p and q can be multiplied together in the following way to
produce a real number value.
p.q = p
x
.q
x
+ p
y
.q
y
+ p
z
.q
z
Figure A2. Summing of vectors
Q
P
S
p
x
p
y
p
z
, , ( ) p
x
p
y
p
z
, , ( ) =
Figure A3. Parametric equations with
vectors
O
R
U
3U
Vector and Matrix algebra 279
The real significance of this
definition is that geometrically
this represents the projection of
one vector onto the other or put
in another way it allows us to
say what the angle q is between
the vectors.
p.q = |p|.|q|. cos
No proof of this relationship
is offered here but you can find
it in the books listed in Appendix B - Bibliography .
A.2.3 Example
If p is the vector (3,6,9) and q is the vector (-2,3,1). What is the sum of
these two vectors and the angle between p and q ?
The sum of p and q is simply the vector (1,9,10)
The length of p = |p| is given by :
The length of q = |q| is similarly:
The scalar product of p.q is then:
(3 x -2) + (6 x 3) + (9 x 1) = 21
Figure A4.
P
Q

p 3
2
6
2
9
2
+ + 126 11.225 = = =
q 2
2
3
2
1
2
+ + 14 3.742 = = =
cos
p q
p q
----------------
21
11.225 3.742
----------------------------------
21
42
------
1
2
--- = = = =
Vector and Matrix algebra 280
The third type of vector multiplication we will leave until we have looked
at some basic properties of matrices.
A.3 Matrices
In one sense matrices are simply rectangular arrays of mathematical
objects which can be manipulated according to a set of rules. In the simplest
case (the only one we are concerned with) the objects are ordinary real num-
bers. The significance of objects in the array depends upon the user. Let us
take a look at a simple example of a matrix:

This is an array of 2 rows and 3 columns. The dimension of the array is 2
x 3. Each number in the array is known as an element of the array. We can
refer to each element by its position in the array. Thus the element 9.1 is in
the first row and the second column and is element 1,2. When we wish to
refer to a complete matrix without listing its elements we will use a bold cap-
ital letter (e.g. A). A vector you may have noticed is simply an ordered list of
three numbers and, if we wish, we can regard it as either a matrix of dimen-
sion 1 x 3 (row vector) or of dimension 3 x 1 (column vector). In this course
all vectors will be column vectors.
In the computer graphics course we are only concerned with matrices of
dimensions 3 x 3 and 4 x 4. These are examples of square matrices. We can
give three useful definitions in terms of the following general 3 x 3 matrix:
The line of elements from a
11
to a
33
is known as the leading diagonal. If
the following is true for all elements not on the leading diagonal a
ij
= a
ji
then
the matrix is symmetric. If on the other hand for all elements not on the lead-
ing diagonal a
ij
= -a
ji
then the matrix is antisymmetric. The matrices repre-
senting rotation in computer graphics are examples of antisymmetric
matrices.
A.4 Arithmetic with matrices
With a fairly obvious restriction the operations of addition, subtraction
and multiplication are easy to define for matrices.
2.0 9.1 0.0
0.5 2.9 1.0


a11 a12 a13
a21 a22 a23
a31 a32 a33





Vector and Matrix algebra 281
Addition and subtraction for the matrices A and B are defined as adding
or subtracting the corresponding elements of the matrices. The obvious
restriction is that the matrices must be of the same dimension.
Example 61. Matrix addition:
With multiplication the definition is a little more complicated. The 'ij'th
element of the product of A and B is formed by considering the 'i'th row of A
as a row vector and the 'j'th column of B as a column vector and then setting
the 'ij'th element to the scalar product of the two vectors. For this to work the
column dimension of A must be the same as the row dimension of B. A
numerical example should make this clear:
Figure 156. Matrix Multiplication
The element 1,2 is calculated from:
Thus a 2 x 3 matrix can be multiplied by a 3 x 2 matrix to give a 2 x 2
matrix. Clearly the product B.A is not defined in this case. With square
matrices both A.B and B.A will be defined but you must be aware that in
most cases
1 2 3
4 5 6


2 5 8
3 1 9


+
3 7 11
7 6 3


=
A B
1 2 3
4 5 6


1 4
2 5
6 1





23 17
55 44


= =
1 2 3 , , ( ) 4 5 1 , , ( ) 1.4 2.5 3.1 + + 17 = =
A B B A
Vector and Matrix algebra 282
This is very clearly illustrated in computer graphics where (in 2-dimen-
sions) translation (T) and rotation (R) are both represented by 3 X 3 matrices
and a rotation followed by a translation (TR) does not produce the same
result as a translation followed by a rotation (RT) Fig. 5.
Example 62. Translating a point using a matrix
The vector v = (1,2,1) is multiplied by the translation matrix T below.
Calculate the translated vector v'
This represents a translation by 10 units in both the x and y directions.
Thus the vector v' is (11,12,1)
A.5 Determinants
Just as forming the scalar product is a rule for calculating a simple number
from a vector which is useful for various applications a similar approach can
be adopted for matrices. In simple terms the determinant of a matrix is a rule
for evaluating the elements of the matrix. This is very much an over-simpli-
fication because determinants are mathematical entities in their own right
with their own set of properties and algebra. However the only fact about
1 - original position
2 - translate 4 units along x
3 - rotate 45
1 - original position
2 - rotation 45
3 - translation 4 units along x
T
1 0 10
0 1 10
0 0 1





=
Tv
1 0 10
0 1 10
0 0 1





1
2
1





11
12
1





= =
Vector and Matrix algebra 283
determinants that you need to know for this course is the rule for evaluating a
3 x 3 determinant. The determinant of the matrix A is usually written as |A|
or det(A). The rule is best explained by considering the simpler case of a 2 x
2 determinant as follows:
If A is the matrix:
then:
For a 3 x 3 determinant the definition is an extension of the above:
If A =
then
= a
11
(a
22
a
33
-a
23
a
32
)-a
12
(a
21
a
33
-a
23
a
31
)+a
13
(a
21
a
32
-a
22
a
31
)
At first this looks a very obscure definition but if you look at it in terms of
the position of the elements you should see the symmetry in the definition. In
practice evaluation is quite easy:
A.6 The vector product of two vectors
We now return to the subject of multiplying two vectors. The vector prod-
uct of two vectors generates a third vector (hence the name) by the following
rule:
a11 a12
a21 a22


det A ( )
a11 a12
a21 a22
a11.a22 a12.a21 ( ) = =
a11 a12 a13
a21 a22 a23
a31 a32 a33





A
a11 a12 a13
a21 a22 a23
a31 a32 a33
a11.
a22 a23
a32 a33


a12
a21 a23
a31 a33


a13
a21 a22
a31 a32


+ = =
Vector and Matrix algebra 284
The vector product of two vectors a and b, with an angle between them,
is the vector whose length is |a|.|b|.sin() and whose direction is perpendicu-
lar to both a and b.
This is usually written:

where n is a unit normal vector perpendicular to the plane containing a
and b.
There are, of course, two directions perpendicular to the plane containing
a and b and n is defined to be in the direction a normal screw or bolt would
travel if it is turned from a to b. The important implication of this is that:
a x b = -b x a

If i,j,k are unit vectors along the three axes X,Y,Z then you should be able
to convince yourself of the following:
i x i = j x j = k x k =0
i x j = k = -j x i
j x k = i = -k x j
k x i = j = -i x k
a b a b ( ) n sin =
x
y
z
a
b
n
Vector and Matrix algebra 285
A.7 The Distributive law
In a similar manner to the scalar product the distributive law holds for the
vector product in the form:
a x (b + c) = a x b + a x c
We can use the distributive law to deduce a useful expression for evaluat-
ing the components of the cross product of the vectors a (a
1
,a
2
,a
3
) and b
(b
1
,b
2
,b
3
) as follows:

This may be written in the form of a determinant:
Find a unit vector perpendicular to the two vectors (4,-2,3) and (5,1,-4)
A vector which is perpendicular to the two vectors is the cross product of
the two vectors. Using the formulae above for the components of a cross
product if
(4,-2,3)X(5,1,-4) = (x,y,z) then
x = ([-2].[-4] - [3].[1]) = 5 y = ([3].[5] - [4].[-4]) = 31
z = ([4].[1] - [-2].[5]) = 14
Thus the vector (5,31,14) is perpendicular to the two vectors it is not,
however a unit vector but we can generate a unit vector by dividing each
component by the length of the vector
The length of the vector is given by:

Thus a unit vector (rounded to three figures) is (0.145,0.902,0.407)
A.8 Parametric Equations
Almost everyone is familiar with the equation of a straight line in two
dimensions:
y = mx + c
in which the points of the line are given by pairs of values (x,y), m is the
line gradient and c the intercept of the line with the Y axis. The equation rep-
resents an infinitely long line but in computer graphics we are most often
Vector and Matrix algebra 286
interested in lines of a finite length. An alternative form of the equation for a
straight line is often more convenient. Suppose we wish to represent a line
from (x1,y1) to (x2,y2) then consider the following two equations :
x = x
1
+ (x
2
- x
1
).t
y = y
1
+ (y
2
- y
1
).t
If t = 0 then x = x
1
and y = y
1
the first point on the line. Similarly if t = 1
then x = x
2
and y = y
2
the last point on the line. In fact all points along the
line segment between (x
1
,y
1
) and (x
2
,y
2
) can be generated by choosing a
value for t between 0 and 1. The equations are the parametric form of the
equation of a straight line with parameter t. The equation of a line segment in
three dimensions can be formed by adding a third equation:
z = z
1
+ (z
2
- z
1
).t
Example 63. Example
The equation of a circle in two dimensions centred on the origin is usually
represented by
x
2
+ y
2
= R
2
As an alternative we can represent this in parametric form as
x = R.Cos()
y = R.Sin()
Here the parameter is the angle with respect to the x axis and ranges
from 0 degrees to 360 degrees (2 radians).
Bibliography 287
Appendix B
Bibliography
Leen Ammeraal, Computer Graphics for Java Programmers, 1998, Wiley -
ISBN 0-471-98142-7
Foley, van Dam, Feiner, Hughes and Philips, Introduction to Computer
Graphics , Addison-Wesley 1993, ISBN 0-20160-921-5
Glenn W Rowe, Computer Graphics with Java -Palgrave, 0-333-92097-X
Patricia Egerton and William Hall, Computer Graphics - Mathematical
First Steps, 1998, Prentice-Hall, ISBN 0-13-599572-8
James Gleick, Chaos, Abacus
Nina Hall, The New Scientist Guide to Chaos, Penguin, 0-14-014571-0