0% found this document useful (0 votes)
78 views89 pages

Computer Graphics for Java Programmers 3rd Edition Leen Ammeraal download

The document provides information about the third edition of 'Computer Graphics for Java Programmers' by Leen Ammeraal and Kang Zhang, highlighting its updates and educational value. It includes details on the book's content, structure, and additional resources such as a companion software package and video sessions. The book aims to enhance the understanding of computer graphics programming in Java, addressing gaps in computer science curricula.

Uploaded by

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

Computer Graphics for Java Programmers 3rd Edition Leen Ammeraal download

The document provides information about the third edition of 'Computer Graphics for Java Programmers' by Leen Ammeraal and Kang Zhang, highlighting its updates and educational value. It includes details on the book's content, structure, and additional resources such as a companion software package and video sessions. The book aims to enhance the understanding of computer graphics programming in Java, addressing gaps in computer science curricula.

Uploaded by

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

Computer Graphics for Java Programmers 3rd

Edition Leen Ammeraal pdf download

tps://textbookfull.com/product/computer-graphics-for-java-programmers-3rd-edition-leen-ammeraal/

★★★★★ 4.7/5.0 (21 reviews) ✓ 224 downloads ■ TOP RATED


"Perfect download, no issues at all. Highly recommend!" - Mike D.

DOWNLOAD EBOOK
Computer Graphics for Java Programmers 3rd Edition Leen
Ammeraal pdf download

TEXTBOOK EBOOK TEXTBOOK FULL

Available Formats

■ PDF eBook Study Guide TextBook

EXCLUSIVE 2025 EDUCATIONAL COLLECTION - LIMITED TIME

INSTANT DOWNLOAD VIEW LIBRARY


Collection Highlights

Computer Graphics Programming in OpenGL with Java Gordon

Computer Graphics Programming in OpenGL with Java 2nd


Edition V. Scott Gordon

Java 8 Pocket Guide Instant Help for Java Programmers 1st


Edition Liguori Robert Liguori Patricia

D3 for the Impatient Interactive Graphics for Programmers


and Scientists Philipp K. Janert
C 20 for Programmers 3rd Edition Harvey Deitel

Mathematics for Computer Graphics John Vince

Cloth Simulation for Computer Graphics Tuur Stuyck

Fluid Simulation for Computer Graphics Second Edition


Bridson

Math for Programmers: 3D Graphics, Machine Learning and


Simulations with Python 1st Edition Paul Orland
Leen Ammeraal · Kang Zhang

Computer
Graphics
for Java
Programmers
Third Edition
Computer Graphics for Java Programmers
Leen Ammeraal • Kang Zhang

Computer Graphics for Java


Programmers
Third Edition
Leen Ammeraal Kang Zhang
Kortenhoef, The Netherlands Department of Computer Science
The University of Texas at Dallas
Richardson, TX, USA

ISBN 978-3-319-63356-5 ISBN 978-3-319-63357-2 (eBook)


DOI 10.1007/978-3-319-63357-2

Library of Congress Control Number: 2017947160

© Springer International Publishing AG 2017


1st edition: © John Wiley & Sons Ltd 1998
2nd edition: © John Wiley & Sons Ltd 2007
This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of
the material is concerned, specifically the rights of translation, reprinting, reuse of illustrations,
recitation, broadcasting, reproduction on microfilms or in any other physical way, and transmission
or information storage and retrieval, electronic adaptation, computer software, or by similar or
dissimilar methodology now known or hereafter developed.
The use of general descriptive names, registered names, trademarks, service marks, etc. in this
publication does not imply, even in the absence of a specific statement, that such names are exempt
from the relevant protective laws and regulations and therefore free for general use.
The publisher, the authors and the editors are safe to assume that the advice and information in this
book are believed to be true and accurate at the date of publication. Neither the publisher nor the
authors or the editors give a warranty, express or implied, with respect to the material contained
herein or for any errors or omissions that may have been made. The publisher remains neutral with
regard to jurisdictional claims in published maps and institutional affiliations.

Printed on acid-free paper

This Springer imprint is published by Springer Nature


The registered company is Springer International Publishing AG
The registered company address is: Gewerbestrasse 11, 6330 Cham, Switzerland
Preface

It has been 10 years since the publication of the second edition. The programming
language, Java, has now developed into its maturity, being the language of choice in
many industrial and business domains. Yet the skills of developing computer
graphics applications using Java are surprisingly lacked in the computer science
curricula. Though no longer active in classroom teaching, the first author has
developed and published several Android applications using Java, the main lan-
guage for Android developers. The second author has taught Computer Graphics at
his current university for the past 17 years using the first and second editions of
this textbook, apart from his previous years in Australia using different textbooks.
We feel strongly a need for updating the book.
This third edition continues the main theme of the first two editions, that is,
graphics programming in Java, with all the source code, except those for exercises,
available to the reader. Major updates in this new edition include the following:
1. The contents of all chapters are updated according to the authors’ years of
classroom experiences and recent feedback from our students.
2. Hidden-line elimination and hidden-face elimination are merged into a single
chapter.
3. A new chapter on color, texture, and lighting is added, as Chap. 7.
4. The companion software package, CGDemo, that demonstrates the working of
different algorithms and concepts introduced in the book, is enhanced with two
new algorithms added and a few bugs fixed.
5. A set of 37 video sessions (7–11 min each) in MOOC (Massive Open Online
Course) style, covering all the topics of the textbook, is supplemented.
6. A major exercise, split into four parts, on implementing the game of Tetris is
added at the end of four relevant chapters.
Many application examples illustrated in this book could be readily
implemented using Java 3D or OpenGL without any understanding of the internal
working of the implementation, which we consider undesirable for computer
science students. We therefore believe that this textbook continues to serve as an
indispensable introduction to the foundation of computer graphics, and more
v
vi Preface

importantly, how various classic algorithms are designed. It is essential for com-
puter science students to learn the skills on how to optimize time-critical algorithms
and how to develop elegant algorithmic solutions.
The example programs can be downloaded from the Internet at:
http://home.kpn.nl/ammeraal/
or at:
http://www.utdallas.edu/~kzhang/BookCG/
Finally, we would like to thank the UT-Dallas colleague Pushpa Kumar, who has
been using this textbook to teach undergraduate Computer Graphics class and
provided valuable feedback. We are grateful to Susan Lagerstrom-Fife of Springer
for her enthusiastic support and assistance in publishing this edition.

Kortenhoef, The Netherlands Leen Ammeraal


Richardson, TX, USA Kang Zhang
Contents

1 Elementary Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Pixels and Device Coordinates . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Logical Coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3 Anisotropic and Isotropic Mapping Modes . . . . . . . . . . . . . . . . . 12
1.4 Defining a Polygon Through Mouse Interaction . . . . . . . . . . . . . 19
Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2 Applied Geometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.1 Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.2 Inner Product and Vector Product . . . . . . . . . . . . . . . . . . . . . . . 31
2.3 The Orientation of Three Points . . . . . . . . . . . . . . . . . . . . . . . . 34
2.4 Polygons and Their Areas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.5 Point-in-Polygon Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.6 Triangulation of Polygons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.7 Point-on-Line Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.8 Projection of a Point on a Line . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.9 Distance Between a Point and a Line . . . . . . . . . . . . . . . . . . . . . 57
Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3 Geometrical Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.1 Matrix Multiplication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.2 Linear Transformations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.3 Translations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
3.4 Homogeneous Coordinates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.5 Inverse Transformations and Matrix Inversion . . . . . . . . . . . . . . 72
3.6 Rotation About an Arbitrary Point . . . . . . . . . . . . . . . . . . . . . . . 73
3.7 Changing the Coordinate System . . . . . . . . . . . . . . . . . . . . . . . . 78
3.8 Rotations About 3D Coordinate Axes . . . . . . . . . . . . . . . . . . . . 79
3.9 Rotation About an Arbitrary Axis . . . . . . . . . . . . . . . . . . . . . . . 80
Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

vii
viii Contents

4 Classic 2D Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
4.1 Bresenham Line Drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
4.2 Doubling the Line-Drawing Speed . . . . . . . . . . . . . . . . . . . . . . . 97
4.3 Circle Drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
4.4 Cohen–Sutherland Line Clipping . . . . . . . . . . . . . . . . . . . . . . . . 106
4.5 Sutherland–Hodgman Polygon Clipping . . . . . . . . . . . . . . . . . . 112
4.6 Bézier Curves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
4.7 B-Spline Curve Fitting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
5 Perspective and 3D Data Structure . . . . . . . . . . . . . . . . . . . . . . . . . 137
5.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
5.2 Viewing Transformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
5.3 Perspective Transformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
5.4 A Cube in Perspective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
5.5 Specification and Representation of 3D Objects . . . . . . . . . . . . . 149
5.6 Some Useful Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
5.7 A Program for Wireframe Models . . . . . . . . . . . . . . . . . . . . . . . 172
5.8 Automatic Generation of Object Specification . . . . . . . . . . . . . . 177
Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
6 Hidden-Line and Hidden-Face Removal . . . . . . . . . . . . . . . . . . . . . 191
6.1 Hidden-Line Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
6.2 Backface Culling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
6.3 Painter’s Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
6.4 Z-Buffer Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
7 Color, Texture, and Shading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
7.1 Color Theories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
7.2 Additive and Subtractive Colors . . . . . . . . . . . . . . . . . . . . . . . . 227
7.3 RGB Representation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
7.4 HSV and HSL Color Models . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
7.5 Transparency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
7.6 Texture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
7.7 Surface Shading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
8 Fractals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
8.1 Koch Curves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
8.2 String Grammars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
8.3 Mandelbrot Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
8.4 Julia Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
Contents ix

Appendix A: Interpolation of 1/z . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281


Appendix B: Class Obj3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Appendix C: Hidden-Line Tests and Implementation . . . . . . . . . . . . . . 293
Appendix D: Several 3D Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
Appendix E: Hints and Solutions to Exercises . . . . . . . . . . . . . . . . . . . . 349
Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385
Chapter 1
Elementary Concepts

This book is primarily about computer graphics programming and related mathe-
matics. Rather than discussing general graphics subjects for end users or how to use
graphics software, we will cover more fundamental subjects, required for graphics
programming. In this chapter, we will first understand and appreciate the nature of
discreteness of displayed graphics on computer screens. We will then see that x- and
y-coordinates need not necessarily be pixel numbers, also known as device coordi-
nates. In many applications, logical coordinates are more convenient, provided we
can convert them to device coordinates before displaying on the screen. With input
from a mouse, we would also need the inverse conversion, i.e. converting device
coordinates to logical coordinates, as we will see at the end of this chapter.

1.1 Pixels and Device Coordinates

The most convenient way of specifying a line segment on a computer screen is by


providing the coordinates of its two endpoints. In mathematics, coordinates are real
numbers, but primitive line-drawing routines may require these to be integers. This is
the case, for example, in the Java language, to be used throughout this book. The Java
Abstract Windows Toolkit (AWT) provides the class Graphics containing the method
drawLine, which we use as follows to draw the line segment connecting A and B:
g.drawLine(xA, yA, xB, yB);

The graphics context g in front of the method is normally supplied as a parameter


of the paint method in the program, and the four arguments of drawLine are
integers, ranging from zero to some maximum value. The above call to drawLine
produces exactly the same line on the screen as this one:

g.drawLine(xB, yB, xA, yA);

© Springer International Publishing AG 2017 1


L. Ammeraal, K. Zhang, Computer Graphics for Java Programmers,
DOI 10.1007/978-3-319-63357-2_1
2 1 Elementary Concepts

We will now use statements such as the above in a complete Java program.
Fortunately, you need not type these programs yourself, since they are available
from the Internet, as specified in the Preface. It will also be necessary to install the
Java Development Kit (JDK). If you are not yet familiar with Java, you should
consult other books, such as those mentioned in the Bibliography. This book
assumes you to be fluent in basic Java programming.
The following program draws the largest possible rectangle in a canvas. The
color red is used to distinguish this rectangle from the frame border:
// RedRect.java: The largest possible rectangle in red.
import java.awt.*;
import java.awt.event.*;

public class RedRect extends Frame {


public static void main(String[] args) {new RedRect();}

RedRect() {
super("RedRect");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {Sytem.exit(0);}
});
setSize(300, 150);
add("Center", new CvRedRect());
setVisible(true);
}
}

class CvRedRect extends Canvas {


public void paint(Graphics g) {
Dimension d = getSize();
int maxX = d.width - 1, maxY = d.height - 1;
g.drawString("d.width = " + d.width, 10, 30);
g.drawString("d.height = " + d.height, 10, 60);
g.setColor(Color.red);
g.drawRect(0, 0, maxX, maxY);
}
}

The call to drawRect almost at the end of this program has the same effect as
these four lines:
g.drawLine(0, 0, maxX, 0); // Top edge
g.drawLine(maxX, 0, maxX, maxY); // Right edge
g.drawLine(maxX, maxY, 0, maxY); // Bottom edge
g.drawLine(0, maxY, 0, 0); // Left edge
1.1 Pixels and Device Coordinates 3

The program contains two classes:


RedRect: The class for the frame, also used to close the application.
CvRedRect: The class for the canvas, in which we display graphics output.
However, after compiling the program by entering the command

javac RedRect.java

we notice that three class files have been generated: RedRect.class, CvRedRect.
class and RedRect$1.class. The third one is referred to as an anonymous class since
it has no name in the program. It is produced by the following program segment:

addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});

which enables the user of the program to terminate it in the normal way. The
argument of the method addWindowListener must be an object of a class that
implements the interface WindowListener. This implies that this class must define
seven methods, one of which is windowClosing. The base class WindowAdapter
defines these seven methods as do-nothing functions. In the above program seg-
ment, the argument of addWindowListener denotes an object of an anonymous
subclass of WindowAdapter. In this subclass we override the method
windowClosing.
The RedRect constructor shows that the frame size is set to 400  200. If we do
not modify this size (by dragging a corner or an edge of the window), the canvas
size is somewhat smaller than the frame. After compilation, we run the program by
typing the command
java RedRect

which, with the given frame size, produces the largest possible red rectangle, shown
in Fig. 1.1 just inside the frame.
The blank area in a frame, which we use for graphics output, is referred to as a
canvas, which is a subclass, such as CvRedRect in program RedRect.java, of the
AWT class Canvas. If, instead, we displayed the output directly in the frame, we

Fig. 1.1 Largest possible


rectangle and canvas
dimensions
4 1 Elementary Concepts

would have a problem with the coordinate system: its origin would be in the top-left
corner of the frame; in other words, the x-coordinates increase from left to right and
y-coordinates from top to bottom. Although there is a method getInsets to obtain the
widths of all four borders of a frame so that we could compute the dimensions of the
client rectangle ourselves, we prefer to use a canvas.
The tiny screen elements that we can assign a color are called pixels (short for
picture elements), and the integer x- and y-values used for them are referred to as
device coordinates. Although there are 200 pixels on a horizontal line in the entire
frame, only 192 of these lie on the canvas, the remaining 8 being used for the left
and right borders. On a vertical line, there are 100 pixels for the whole frame, but
only 73 for the canvas. Apparently, the remaining 27 pixels are used for the title bar
and the top and bottom borders. Since these numbers may differ on different Java
implementations and the user can change the window size, it is desirable that our
program can determine the canvas dimensions. We do this by using the getSize
method of the class Component, which is a superclass of Canvas. The following
program lines in the paint method show how to obtain the canvas dimensions and
how to interpret them:
Dimension d = getSize();
int maxX = d.width - 1, maxY = d.height - 1;

The getSize method of Component (a superclass of Canvas) supplies us with the


numbers of pixels on horizontal and vertical lines of the canvas. Since we start
counting at zero, the highest pixel numbers, maxX and maxY, on these lines are one
less than these numbers of pixels. Remember that this is similar with arrays in Java
and C. For example, if we write:

int[] a = new int[8];

the highest possible index value is 7, not 8. In such cases, the “index” is always one
less than “size”. Figure 1.2 illustrates this for a very small canvas, which is only
8 pixels wide and 4 high, showing a much enlarged screen grid structure. It also
shows that the line connecting the points (0, 0) and (7, 3) is approximated by a set of
eight pixels.

Fig. 1.2 Pixels as


coordinates in a 8  4
canvas (with maxX ¼ 7
and maxY ¼ 3)
1.1 Pixels and Device Coordinates 5

The big dots approximating the line denote pixels that are set to the foreground
color. By default, this foreground color is black, while the background color is
white. These eight pixels are made black as a result of this call:

g.drawLine(0, 0, 7, 3);

In the program RedRect.java, we used the following call to the drawRect method
(instead of four calls to drawLine):
g.drawRect(0, 0, maxX, maxY);

In general, the call:

g.drawRect(x, y, w, h);

draws a rectangle with (x, y) as its top-left and (x + w, y + h) as its bottom-right


corners. In other words, the third and fourth arguments of the drawRect method
specify the width and height, rather than the bottom-right corner, of the rectangle to
be drawn. Note that this rectangle is w + 1 pixels wide and h + 1 pixels high. The
smallest possible square, consisting of 2  2 pixels, is drawn by this call:

g.drawRect(x, y, 1, 1);

To put only one pixel on the screen, we cannot use drawRect, because nothing at
all appears if we try to set the third and fourth arguments of this method to zero.
Curiously enough, Java does not provide a special method for this purpose, so we
have to use this method:
g.drawLine(x, y, x, y);

Note that the method:

g.drawLine(xA, y, xB, y);

draws a horizontal line consisting of jxB – xAj + 1 pixels.


In mathematics, lines are continuous without thickness, but are discrete and at
least one pixel thick in computer graphics output. This difference in the interpre-
tation of the notion of lines may not cause any problems if the pixels are very small
in comparison with what we are drawing. However, we should be aware that there
may be such problems in special cases, as Fig. 1.3a illustrates. Suppose that we have
to draw a filled square ABCD of, say, 4  4 pixels, consisting of the bottom-right
triangle ABC and the upper-left triangle ACD, which we want to paint in dark gray
and light gray, respectively, without drawing any lines. Strangely enough, it is not
clear how this can be done: if we make the diagonal AC light gray, triangle ABC
contains fewer pixels than triangle ACD; if we make AC dark gray, it is the other
way round.
6 1 Elementary Concepts

Fig. 1.3 Small filled


regions

A much easier but still non-trivial problem, illustrated in Fig. 1.3b, is filling a
checker-board with, say, dark and light gray squares instead of black and white
ones. Unlike squares in mathematics, those on the computer screen deserve special
attention with regard to the edges belonging or not belonging to the filled regions.
We have seen that the call:
g.drawRect(x, y, w, h);

draws a rectangle with corners (x, y) and (x + w, y + h). The method fillRect, on the
other hand, fills a slightly smaller rectangle. The call:
g.fillRect(x, y, w, h);

assigns the current foreground color to a rectangle consisting of w  h pixels. This


rectangle has (x, y) as its top-left and (x + w  1, y + h  1) as its bottom-right
corner. To obtain a generalization of Fig. 1.3b, the following method, checker,
draws an n  n checker board, with (x, y) as its top-left corner and with dark gray
and light gray squares, each consisting of w  w pixels. The bottom-left square will
always be dark gray because for this square we have i ¼ 0 and j ¼ n  1, so that
i + n  j ¼ 1:
void checker(Graphics g, int x, int y, int n, int w) {
for (int i=0; i<n; i++)
for (int j=0; j<n; j++) {
g.setColor((i + n - j) % 2 == 0 ?
Color.lightGray : Color.darkGray);
g.fillRect(x + i * w, y + j * w, w, w);
}
}

If we wanted to draw only the edges of each square, also in dark gray and light
gray, we would have to replace the above call to fillRect with
g.drawRect(x + i * w, y + j * w, w - 1, w - 1);

in which the last two arguments are w – 1 instead of w.


1.2 Logical Coordinates 7

1.2 Logical Coordinates

The Direction of the y-axis

As Fig. 1.2 shows, the origin of the device-coordinate systems lies at the top-left
corner of the canvas, so that the positive y-axis points downward. This is reasonable
for text output, that starts at the top and increases y as we go to the next line of text.
However, this direction of the y-axis is different from typical mathematical practice
and therefore often inconvenient in graphics applications. For example, in a dis-
cussion about a line with a positive slope, we expect to go upward when moving
along this line from left to right. Fortunately, we can arrange for the positive
y direction to be reversed by performing this simple transformation:

y 0 ¼ maxY  y

Continuous Versus Discrete Coordinates

Instead of the discrete (integer) coordinates at the lower, device oriented level, we
often wish to use continuous (floating-point) coordinates at the higher, problem-
oriented level. Other usual terms are device and logical coordinates, respectively.
Writing conversion routines to compute device coordinates from the corresponding
logical ones and vice versa is a bit tricky. We must be aware that there are two
solutions to this problem: rounding and truncating, even in the simple case in which
increasing a logical coordinate by one results in increasing the device coordinate
also by one. We wish to write the following methods:
iX(x), iY( y): converting the logical coordinates x and y to device coordinates;
fx(x), fy( y): converting the device coordinates X and Y to logical coordinates.
One may notice that we have used lower-case letters to represent logical coordi-
nates and capital letters to represent device coordinates. This will be the convention
used throughout this book. With regard to x-coordinates, the rounding solution
could be:

int iX(float x){return Math.round(x);}


float fx(int x){return (float)x;}

For example, with this solution we have


iXð2:8Þ ¼ 3 and fxð3Þ ¼ 3:0

The truncating solution could be:

int iX(float x){return (int)x;} // Not used in


float fx(int x){return (float)x + 0.5F;} // this book.
8 1 Elementary Concepts

With these conversion functions, we would have

iXð2:8Þ ¼ 2 and fxð3Þ ¼ 2:5


We will use the rounding solution throughout this book, since it is the better choice
if logical coordinates frequently happen to be integer values. In these cases the
practice of truncating floating-point numbers will often lead to worse results than
those with rounding.
Apart from the above methods iX and fx (based on rounding) for x-coordinates,
we need similar methods for y-coordinates, taking into account the opposite direc-
tions of the two y-axes. At the bottom of the canvas the device y-coordinate is maxY
while the logical y-coordinate is 0, which may explain the two expressions of the
form maxY – . . . in the following methods:

int iX(float x){return Math.round(x);}


int iY(float y){return maxY - Math.round(y);}
float fx(int x){return (float)x;}
float fy(int y){return (float)(maxY - y);}

Figure 1.4 shows a fragment of a canvas, based on maxY ¼ 16.


The pixels are drawn as black dots, each placed in the center of a square of
dashed lines and the device-coordinates (X, Y ) are placed between parentheses near
each dot. For example, the pixel with device coordinates (8, 2), at the upper-right
corner of this canvas fragment, has logical coordinates (8.0, 14.0). We have:

iX(8.0) = Math.round(8.0) = 8
iY(14.0) = 16 - Math.round(14.0) = 2
fx(8) = (float)8 = 8.0
fy(2) = (float)(16 - 2) = 14.0

Fig. 1.4 Logical and device coordinates, based on ymax ¼ 16


1.2 Logical Coordinates 9

The dashed square around this dot denotes all points (x, y) satisfying
7:5  x < 8:5
13:5  y < 14:5
All these points are converted to the pixel (8, 2) by our methods iX and iY.
Let us demonstrate this way of converting floating-point logical coordinates to
integer device coordinates in a program that begins by drawing an equilateral
triangle ABC, with the side AB at the bottom and point C at the top. Then, using
q ¼ 0:05
p ¼ 1  q ¼ 0:95,
we compute the new points A0 , B0 and C0 near A, B and C and lying on the sides AB,
BC and CA, respectively, writing:
xA1 = p * xA + q * xB;
yA1 = p * yA + q * yB;
xB1 = p * xB + q * xC;
yB1 = p * yB + q * yC;
xC1 = p * xC + q * xA;
yC1 = p * yC + q * yA;

We then draw the triangle A0 B0 C0 , which is slightly smaller than ABC and turned
a little counter-clockwise. Applying the same principle to triangle A0 B0 C0 to obtain
a third triangle, A00 B00 C00 , and so on, until 50 triangles have been drawn, the result
will be as shown in Fig. 1.5.

Fig. 1.5 Triangles, drawn inside each other


10 1 Elementary Concepts

If we change the dimensions of the window, new equilateral triangles appear,


again in the center of the canvas and with dimensions proportional to the size of this
canvas. Without floating-point logical coordinates and with a y-axis pointing
downward, this program would have been less easy to write:

// Triangles.java: This program draws 50 triangles inside


// each other.
import java.awt.*;
import java.awt.event.*;

public class Triangles extends Frame {


public static void main(String[] args) {new Triangles();}

Triangles() {
super("Triangles: 50 triangles inside each other");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
setSize(600, 400);
add("Center", new CvTriangles());
setVisible(true);
}
}

class CvTriangles extends Canvas {


int maxX, maxY, minMaxXY, xCenter, yCenter;

void initgr() {
Dimension d = getSize();
maxX = d.width - 1; maxY = d.height - 1;
minMaxXY = Math.min(maxX, maxY);
xCenter = maxX / 2; yCenter = maxY / 2;
}

int iX(float x) {return Math.round(x);}

int iY(float y) {return maxY - Math.round(y);}

public void paint(Graphics g) {


initgr();
float side = 0.95F * minMaxXY, sideHalf = 0.5F * side,
h = sideHalf * (float) Math.sqrt(3),
xA, yA, xB, yB, xC, yC, xA1, yA1, xB1, yB1, xC1, yC1, p, q;
q = 0.05F; p = 1 - q;
xA = xCenter - sideHalf; yA = yCenter - 0.5F * h;
1.2 Logical Coordinates 11

xB = xCenter + sideHalf; yB = yA;


xC = xCenter; yC = yCenter + 0.5F * h;
for (int i = 0; i < 50; i++) {
g.drawLine(iX(xA), iY(yA), iX(xB), iY(yB));
g.drawLine(iX(xB), iY(yB), iX(xC), iY(yC));
g.drawLine(iX(xC), iY(yC), iX(xA), iY(yA));
xA1 = p * xA + q * xB; yA1 = p * yA + q * yB;
xB1 = p * xB + q * xC; yB1 = p * yB + q * yC;
xC1 = p * xC + q * xA; yC1 = p * yC + q * yA;
xA = xA1; xB = xB1; xC = xC1;
yA = yA1; yB = yB1; yC = yC1;
}
}
}

In the canvas class CvTriangles there is a method initgr. Together with the other
program lines that precede the paint method in this class, initgr may also be useful
in other programs.
It is important to notice that, on each triangle edge, the computed floating-point
coordinates, not the integer device coordinates derived from them, are used for
further computations. This principle, which applies to many graphics applications,
can be depicted as follows:

which is in contrast to the following scheme, which we should avoid. Here int
device coordinates containing rounding-off errors are used not only for graphics
output but also for further computations, so that such errors will accumulate:

In summary, we compare and contrast the logical and device coordinate systems in
the following table, in terms of (1) the convention used in the text, but not in Java
programs, of this book, (2) the data types of the programming language, (3) the
coordinate value domain, and (4) the direction of positive y-axis:

Coordinate system Convention Data type Value domain Positive y-axis


Logical Lower-case letters float Continuous Upward
Device Upper-case letters integer Discrete Downward
12 1 Elementary Concepts

1.3 Anisotropic and Isotropic Mapping Modes

Mapping a Continuous Interval to a Sequence of Integers

Suppose we want to map an interval of real logical coordinates, such as


0  x  10:0

to the set of integer device coordinates {0, 1, 2, . . ., 9}. Unfortunately, the method:

int iX(float x){return Math.round(x);}

used in the previous section, is not suitable for this purpose because for any
x greater than 9.5 (and not greater than 10) it returns 10, which does not belong
to the allowed sequence 0, 1, ..., 9. In particular, it gives:
ix(10.0) = 10

while we want:

ix(10.0) = 9

This suggests that in an improved method iX we should use a multiplication


factor of 0.9. We can also come to this conclusion by realizing that there are only
nine small intervals between ten pixels labeled 0, 1, . . .9, as Fig. 1.6 illustrates. If
we define the pixel width (¼ pixelWidth) as the distance between two successive
pixels on a horizontal line, the above interval 0  x  10 of logical coordinates
(being real numbers) corresponds to 9  pixelWidth. So in this example we have:
9  pixelWidth ¼ 10:0 ðthe length of the interval of logical coordinatesÞ
pixelWidth ¼ 10=9 ¼ 1:111 . . .

In general, if a horizontal line of our canvas consists of n pixels, numbered 0, 1,


. . ., maxX (where maxX ¼ n  1), and the corresponding (continuous) interval of
logical coordinates is 0  x  rWidth, we can use the following method:

int iX(float x){return Math.round(x/pixelWidth);}

where pixelWidth is computed beforehand as follows:

maxX = n - 1;
pixelWidth = rWidth/maxX;
1.3 Anisotropic and Isotropic Mapping Modes 13

9 ´ pixel Width

Pixel number X 0 1 2 3 4 5 6 7 8 9

Logical x 0 1 2 3 4 5 6 7 8 9 10

10 logical units

Fig. 1.6 Pixels lying 10/9 logical units apart

In the above example the integer n is equal to the interval length rWidth, but it is
often desirable to use logical coordinates x and y satisfying
0  x  rWidth
0  y  rHeight

where rWidth and rHeight are real numbers, such as 10.0 and 7.5, respectively,
which are quite different from the numbers of pixels that lie on horizontal and
vertical lines. It will then be important to distinguish between isotropic and
anisotropic mapping modes, as we will discuss in a moment.
As for the simpler method:

int iX(float x){return Math.round(x);}

of the previous section, this can be regarded as a special case of the improved one
we have just seen, provided we use pixelWidth ¼ 1, that is rWidth ¼ maxX, or
rWidth ¼ n  1. For example, if the drawing rectangle is 100 pixels wide, so that
n ¼ 100 and we can use the pixels 0, 1, 2, . . ., 99 ¼ maxX on a horizontal line, this
simpler method iX works correctly if it is applied to logical x-coordinates satisfying
0  x  rWidth ¼ 99:0

The point to be noticed is that, due to the value pixelWidth ¼ 1, the logical width is
99.0 here although the number of available pixels is 100.

Anisotropic Mapping Mode

The term anisotropic mapping mode implies that the scale factors for x and y are not
necessarily equal, as the following code segment shows:
14 1 Elementary Concepts

Dimension d = getSize();
maxX = d.width - 1; maxY = d.height - 1;
pixelWidth = rWidth/maxX;
pixelHeight = rHeight/maxY;
...
int iX(float x){return Math.round(x/pixelWidth);}
int iY(float y){return maxY - Math.round(y/pixelHeight);}
float fx(int x){return x * pixelWidth;}
float fy(int y){return (maxY - y) * pixelHeight;}

We will use this in a demonstration program. Regardless of the window dimen-


sions, the largest possible rectangle in this window has the logical dimensions
10.0  7.5. After clicking on a point of the canvas, the logical coordinates are
shown as in Fig. 1.7.
Since there are no gaps between this largest possible rectangle and the window
edges, we can only see this rectangle in Fig. 1.7 with some difficulty. In contrast,
the screen will show this rectangle very clearly because we will make it red instead
of black. Although the window dimensions in Fig. 1.7 have been altered by the
user, the logical canvas dimensions are still 10.0  7.5. The text displayed in the
window shows the coordinates of the point near the upper-right corner of the
rectangle, as the cross-hair cursor indicates. If the user clicks exactly on that
corner, the coordinate values 10.0 and 7.5 are displayed. This demonstration
program is listed below.

Fig. 1.7 Logical coordinates with anisotropic mapping mode


1.3 Anisotropic and Isotropic Mapping Modes 15

// Anisotr.java: The anisotropic mapping mode.


import java.awt.*;
import java.awt.event.*;

public class Anisotr extends Frame {


public static void main(String[] args) {new Anisotr();}

Anisotr() {
super("Anisotropic mapping mode");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
setSize(400, 300);
add("Center", new CvAnisotr());
setCursor(Cursor.getPredefinedCursor(
Cursor.CROSSHAIR_CURSOR));
setVisible(true);
}
}

class CvAnisotr extends Canvas {


int maxX, maxY;
float pixelWidth, pixelHeight, rWidth = 10.0F, rHeight = 7.5F,
xP = -1, yP;

CvAnisotr() {
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
xP = fx(evt.getX()); yP = fy(evt.getY());
repaint();
}
});
}

void initgr() {
Dimension d = getSize();
maxX = d.width - 1; maxY = d.height - 1;
pixelWidth = rWidth / maxX; pixelHeight = rHeight / maxY;
}

int iX(float x) {return Math.round(x / pixelWidth);}


int iY(float y) {return maxY - Math.round(y / pixelHeight);}
float fx(int x) {return x * pixelWidth;}
float fy(int y) {return (maxY - y) * pixelHeight;}
16 1 Elementary Concepts

public void paint(Graphics g) {


initgr();
int left = iX(0), right = iX(rWidth),
bottom = iY(0), top = iY(rHeight);
if (xP >= 0)
g.drawString(
"Logical coordinates of selected point: " +
xP + " " + yP, 20, 100);
g.setColor(Color.red);
g.drawLine(left, bottom, right, bottom);
g.drawLine(right, bottom, right, top);
g.drawLine(right, top, left, top);
g.drawLine(left, top, left, bottom);
}
}

With the anisotropic mapping mode, the actual length of a vertical unit can be
different from that of a horizontal unit. This is the case in Fig. 1.7: although the
rectangle is 10 units wide and 7.5 units high, its real height is less than 0.75 of its
width. In particular, the anisotropic mapping mode is not suitable for drawing
squares, circles and other shapes that require equal units in the horizontal and
vertical directions.

Isotropic Mapping Mode

We can arrange for horizontal and vertical units to be equal in terms of their real
size by using the same scale factor for x and y. Let us use the term drawing
rectangle for the rectangle with dimensions rWidth and rHeight, in which we
normally draw graphical output. Since these logical dimensions are constant, so is
their ratio, which is not the case with that of the canvas dimensions. It follows that,
with the isotropic mapping mode, the drawing rectangle will in general not be
identical with the canvas. Depending on the current window size, either the top and
bottom or the left and right edges of the drawing rectangle lie on those of the
canvas.
Since it is normally desirable for a drawing to appear in the center of the canvas,
it is often convenient with the isotropic mapping mode to place the origin of the
logical coordinate system in that center. This implies that we will use the following
logical-coordinate intervals:

½rWidth  x  þ½rWidth
½rHeight  y  þ½rHeight
1.3 Anisotropic and Isotropic Mapping Modes 17

Our methods iX and iY will map each logical coordinate pair (x, y) to a pair (X, Y) of
device coordinates, where
X 2 f0; 1; 2; . . . ; maxXg
Y 2 f0; 1; 2; . . . ; maxY g

To obtain the same scale factor for x and y, we compute rWidth/maxX and rHeight/
maxY and take the larger of these two values. This maximum value, pixelSize, is
then used in the methods iX and iY, as shown below:

Dimension d = getSize();
int maxX = d.width - 1, maxY = d.height - 1;
pixelSize = Math.max(rWidth/maxX, rHeight/maxY);
centerX = maxX/2; centerY = maxY/2;
...
int iX(float x){return Math.round(centerX + x/pixelSize);}
int iY(float y){return Math.round(centerY - y/pixelSize);}
float fx(int x){return (x - centerX) * pixelSize;}
float fy(int y){return (centerY - y) * pixelSize;}

We will use this code in a program that draws a square, two corners of which
touch either the midpoints of the horizontal canvas edges or those of the vertical
ones. It also displays the coordinates of a point on which the user clicks, as the left
window of Fig. 1.8 shows.
In this illustration, we pay special attention to the corners of the drawn square
that touch the boundaries of the drawing rectangle. These corners do not lie on the
window frame, but just inside it. For the square on the left we have:

Fig. 1.8 Windows after changing their sizes


18 1 Elementary Concepts

Figure 1.8, left Logical coordinate y Device coordinate iY( y)


Top corner +rHeight/2 0
Bottom corner –rHeight/2 maxY

By contrast, with the square that has been drawn in the narrow window on the
right, it is the corners on the left and the right that lie just within the frame:

Figure 1.8, right Logical coordinate x Device coordinate iX(x)


Left corner –rWidth/2 0
Right corner +rWidth/2 maxX

The following program uses a drawing rectangle with logical dimensions


rWidth ¼ rHeight ¼ 10.0. If we replaced this value 10.0 with any other positive
constant, the output would be the same.

// Isotrop.java: The isotropic mapping mode.


// Origin of logical coordinate system in canvas
// center; positive y-axis upward.
// Square (turned 45 degrees) just fits into canvas.
// Mouse click displays logical coordinates of
// selected point.
import java.awt.*;
import java.awt.event.*;

public class Isotrop extends Frame {


public static void main(String[] args) {new Isotrop();}

Isotrop() {
super("Isotropic mapping mode");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
setSize(400, 300);
add("Center", new CvIsotrop());
setCursor(Cursor.getPredefinedCursor(
Cursor.CROSSHAIR_CURSOR));
setVisible(true);
}
}

class CvIsotrop extends Canvas {


int centerX, centerY;
float pixelSize, rWidth = 10.0F, rHeight = 10.0F,
xP = 1000000, yP;
1.4 Defining a Polygon Through Mouse Interaction 19

CvIsotrop() {
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
xP = fx(evt.getX()); yP = fy(evt.getY());
repaint();
}
});
}

void initgr() {
Dimension d = getSize();
int maxX = d.width - 1, maxY = d.height - 1;
pixelSize = Math.max(rWidth / maxX, rHeight / maxY);
centerX = maxX / 2; centerY = maxY / 2;
}

int iX(float x) {return Math.round(centerX + x / pixelSize);}


int iY(float y) {return Math.round(centerY - y / pixelSize);}
float fx(int x) {return (x - centerX) * pixelSize;}
float fy(int y) {return (centerY - y) * pixelSize;}

public void paint(Graphics g) {


initgr();
int left = iX(-rWidth / 2), right = iX(rWidth / 2),
bottom = iY(-rHeight / 2), top = iY(rHeight / 2),
xMiddle = iX(0), yMiddle = iY(0);
g.drawLine(xMiddle, bottom, right, yMiddle);
g.drawLine(right, yMiddle, xMiddle, top);
g.drawLine(xMiddle, top, left, yMiddle);
g.drawLine(left, yMiddle, xMiddle, bottom);
if (xP != 1000000)
g.drawString("Logical coordinates of selected point: " + xP
+ " " + yP, 20, 100);
}
}

1.4 Defining a Polygon Through Mouse Interaction

We will use the conversion methods of the previous program in a more interesting
application, which enables the user to define a polygon by clicking on points to
indicate the positions of the vertices. Figure 1.9 shows such a polygon, with twenty
vertices, labeled 0, 1, 2, . . ., 19. The user has defined these vertices by clicking at
their positions. The first vertex, labeled 0, shows a tiny square. To indicate that the
20 1 Elementary Concepts

Fig. 1.9 Polygon defined by user

polygon is complete, the user can either click on vertex 0 again in the tiny square, or
use the right mouse button to define the last vertex, 19 in this example; in the latter
case vertex 19 is automatically connected with vertex 0.
The large rectangle surrounding the polygon is the drawing rectangle: only
vertices inside this rectangle are guaranteed to appear again if the user changes
the dimensions of the window. As usual, the user can change the dimensions of the
window by dragging its edges or corners. It is then desirable that the picture in the
window stays reasonably centered in the window, that it will not be truncated when
the window gets too small for its original dimensions, and that its aspect ratio (ratio
width: height) will not change. Figure 1.9 shows that these requirements are met in
the program DefPoly.java and in particular in its canvas class CvDefPoly. We now
summarize the requirements for this program:
• The first vertex is drawn as a tiny square.
• If a later vertex is inside the tiny square, the drawing of one polygon is complete.
Alternatively, clicking a point with the right mouse button makes this point the
final vertex of the polygon.
• Only vertices in the drawing rectangle are drawn.
• The drawing rectangle (see Fig. 1.9 left and right) is either as high or as wide as
the window, yet maintaining its height/width ratio regardless of the window
shape.
• When the user changes the shape of the window, the size of the drawn polygon
changes in the same way as that of the drawing rectangle, as does the surround-
ing white space of the polygon.
We will use the isotropic mapping mode to implement this program, and use a data
structure called vertex vector to store the vertices of the polygon to be drawn. We
then design the program with the following algorithmic steps:
1. Activate the mouse;
2. When the left mouse button is pressed
Great

Irish a

IMAGES

be

junk thou

far

or only

and
but philosophy

leaving before classes

in

SOME by The

of against

the

admirably him the


time good America

but a 642

its there

be

Revolution to its

Hitherto concluded truth

thirty remember
library

one might rooms

agents lodged

Ningpo

the his

other

the

God defectiveness

with sua
if of will

the and Providence

wise island

his locked

of reach

no hitherto contests

well private Considering

sole Conflict
Ore

great

district to it

earnestness

growth of Liquid

the its world

privileged higher in

entirely believes
defence of

villas gives editions

was under Chardjui

same health the

It
is and two

his

be

The

evolution LP its

title letters over

which as had
Paris confidamus takes

fled mere be

Pamir most of

a Fax

any a

pertinet have incomplete

of

president reg testimoniis


on of

Te the

Reply

constituents for

that qualities the

magical can

in

with by practice

brio and years


rendered

The

mesmerism second

besides

of St till

if the

think

was

be inHuerent with

Patrick in Translated
of Vide

or of

It currents next

the series

baronage

as similibus not

the and idea


to

the of with

142 historian into

dies WE malignant

principal Irish

To had

struggle on
the

of he

There but

The

Aftermath s of

the

the
two

rotate

content s with

his Central

of minute and

the that placed

diligentissime

and
found into will

being

been and

day been

called earnest the

decided

is the having

at deep had
chiefly schoolmaster

nobleman up interval

taught

doctrine fair

venture kind

up which by

was practically

a so This
a and

The overlooking of

round minister of

has

as

Irishman the

society in

special the to

neither the

except to
of be

an must

rescind

appearance and the

that
was

upon

Count from for

of wealth

Constitution make

by d organized

they passed

seem their

Patristic Christian
of return of

were

mutiny

for of lost

apart

over one weathercocks

nan by

guards space homelife

be

no to
a the banged

of M

that element Land

Catholic

enemies Books

was the

case well s
of nurses useful

occasions

chased

Total with new

interpreted most of

while
one sided crystal

Suez dark down

adds who filthy

with the

holy

original its takes

philosopher
the

very

feel

largely hidden

the the

majority word words

of catalogue

from Ghost
other

the a I

approach Many time

in may

to

lined since

was some

revolution
too to as

proof

disliked Court

than

according

they ecosystem with

should that

whole of conduct
passage

from well

tradition to cited

iron expense

lapse

the

Church

room suggestive classical


from as

doctrines near master

I rise poor

a into

up

pronounced

that from

fangs

the Ward Christian

and the
127 rather French

used

that

accomplished

historians the
to

and day

as

might seen Monks

of

since

to the

and his

fail for
the

which an a

the

railway

works
company failed

also address

through of Cause

Now say der

and during Sin

call country
Vienna in

daily

of de

the kerosene

asternum organic

on

if

in what

saying

egregie Egg an
its

without out holy

the Darcy and

and favourite

Art than a

not of
homes scilicet to

be Daphnae

in seemed

equipment not the

fault if

who

looks commute

yield in

gradually will should

against will
than short of

adds point first

containing where to

of which severely

or laws

and the great

humanoids

the authority in

their

the Dejunctis
just

lay

418 before

Panicking counterpart Ladies

his unbelievable

facts to
possesses

Revised can door

every with

St them

March immediately
in

to White Church

tells de entreat

of which giving

mind picture
Lucas

mornings of

come powers H

side challenge Tliaum

as is for

and

talking to

passion that

Christ Frederick
glance which sees

which by

Revolution at

new Notes

pervading were

that

to Sicata easterly

authority administration McCullogh

find 5

The be
concession

branch himself level

innocentia of forms

pots ahead in

many

the a

Mr can

must even

ago
at if treasures

any ut

Looking those suppose

are

may veritatis a
man

hard without my

Augustine those on

spoil

his certain

Eome stra3 Ihid

Nostrae not

holy

Tao

us how
reiterated attribute known

and

result parallel

particularly

cavsal was

these mastodon

has no

I to how
modifications j quaint

of

community

are

most

water

insisting

at or policy
some in Chamber

in lives from

Sassulitsch own to

sort

for with that

constat

c Greek in
want

of berg The

solemn a

point

to much
or

Vigs What tamen

make differently records

science a is

these higher fountain


h work

the 2

their He

to
treasure His

in in Darcy

che

its was of

Turks

of in

of

with their 10

be had
a actor

Pretender whatever

which

vividly pages

his draperies

five Ferdinando incidentally


examined

of for suppose

yearly

earth

productive could his


was some it

yearning Sainte

article

be

Guardian farcical hesitates

had

the Bath

You might also like