You are on page 1of 53

Computer Graphics for Java

Programmers 3rd Edition Leen


Ammeraal
Visit to download the full and correct content document:
https://textbookfull.com/product/computer-graphics-for-java-programmers-3rd-edition-l
een-ammeraal/
More products digital (pdf, epub, mobi) instant
download maybe you interests ...

Computer Graphics Programming in OpenGL with Java


Gordon

https://textbookfull.com/product/computer-graphics-programming-
in-opengl-with-java-gordon/

Computer Graphics Programming in OpenGL with Java 2nd


Edition V. Scott Gordon

https://textbookfull.com/product/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

https://textbookfull.com/product/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

https://textbookfull.com/product/d3-for-the-impatient-
interactive-graphics-for-programmers-and-scientists-philipp-k-
janert/
C 20 for Programmers 3rd Edition Harvey Deitel

https://textbookfull.com/product/c-20-for-programmers-3rd-
edition-harvey-deitel/

Mathematics for Computer Graphics John Vince

https://textbookfull.com/product/mathematics-for-computer-
graphics-john-vince/

Cloth Simulation for Computer Graphics Tuur Stuyck

https://textbookfull.com/product/cloth-simulation-for-computer-
graphics-tuur-stuyck/

Fluid Simulation for Computer Graphics Second Edition


Bridson

https://textbookfull.com/product/fluid-simulation-for-computer-
graphics-second-edition-bridson/

Math for Programmers: 3D Graphics, Machine Learning and


Simulations with Python 1st Edition Paul Orland

https://textbookfull.com/product/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
Another random document with
no related content on Scribd:
There they found Laddie wide awake, sitting in the assembly room
of the station house, while several officers, who were on reserve
duty, were laughing and joking with him.
“He’s far from being asleep,” said Mr. North.
“I should say so!” agreed Mr. Bunker. “Laddie boy, what in the
world are you doing down here?” he asked the little fellow.
“I came down to find out about a riddle,” he answered.
“And he’s had us all guessing riddles ever since he walked in here
about an hour ago,” chuckled the police sergeant in charge of the
station. “He’s a great boy!”
“I didn’t perzactly come down here to ask riddles,” said Laddie.
“But I wanted to make up a riddle about a policeman to ask Farmer
Joel when I got to the farm, and I had to see a police station inside to
make up the riddle.”
“Well, did you make the riddle up?” asked the sergeant, with
another laugh. Life at the station was very often dull, and the men on
duty welcomed any little change.
“Yes, I got a riddle,” Laddie announced. “’Tisn’t very good, but
maybe I can think of a better one after a while. This is it. Why is a
police station like a candy shop?”
“Ha! Ha!” laughed the sergeant. “That may be a riddle, but I can’t
see it. Nothing could be more different than a candy store and this
police station.”
“Yes, there’s something alike in each of them,” went on Laddie.
“Do you all give up?” he asked. “Can you tell why a police station is
like a candy shop?”
“Is it because when people are brought here they have to stick?”
asked Adam.
“Ha! Ha! That’s pretty good!” laughed the sergeant. “I’d never think
of that myself! Pretty good! A police station is like a candy shop
because people have to stick here! And it’s true! They do have to
stick if we arrest them and put them in a cell. And if there’s sticky
candy on the floor of a candy shop they’d stick there. Pretty good!”
“No, that isn’t the reason,” said Laddie. “Listen. I’ll tell you. A police
station is like a candy shop because it’s full of sticks. Sticks, you
know—the policemen’s clubs. They’re like sticks of candy, you
know!”
“Ha! Ha!” laughed the sergeant again. “That’s pretty good! I must
remember that to tell the captain. Well, good night to you,” he added,
as Mr. Bunker led Laddie out, thanking the sergeant and his men for
having entertained and kept the little boy.
On the way home in the automobile Mr. Bunker said Laddie should
not have slipped off and gone down the street to the police station
without telling some one about it.
“We were all worried, Laddie,” went on his father.
“I’m sorry,” the little fellow said. “I won’t do it again. But I got to
thinking I could make up a good riddle about a policeman, and I
thought it would be better if I could see one before I made the riddle,
so I just went.”
“Well, it’s a pretty good riddle—I’ll say that,” chuckled Adam North.
“Maybe you can make up some about the farm when you get there.
Farmer Joel likes jokes and riddles.”
“I’ll make up a lot of them for him,” kindly offered Laddie, as if he
had a stock of riddles constantly on hand and could turn them out at
a moment’s notice.
“Oh, Laddie, you bad boy, where have you been?” asked his
mother when he reached home.
When they told her his riddle about the police station and candy
shop, she could not help laughing.
A few days after this everything was ready for the start to Farmer
Joel’s. Mr. Bunker had arranged to leave his real estate business in
charge of his men at the office, and Mrs. Bunker prepared to close
the house, taking Norah with her to cook at the farm.
The children’s clothing had been packed in valises and trunks, and
piled in the big auto truck which was filled with straw to make a
comfortable resting place for the six little Bunkers on their forty-mile
trip.
As I have told you, the children and their father would ride in the
big truck with Adam, and Mrs. Bunker would follow with Norah in the
touring car, the children’s mother doing the driving.
All was one grand excitement in the home of the six little Bunkers
when the morning came on which they were to leave for the farm.
Every one seemed to be talking at once, and certainly the children,
Violet especially, never seemed to have asked so many questions
before.
Laddie, too, was on the alert. He was working on a new riddle. He
spoke of it to Russ.
“It’s about a tree,” said Laddie.
“Oh, I know that old riddle,” Russ said. “You mean why is a tree
like a dog? Because it has a bark.”
“No, it isn’t that one,” Laddie said eagerly. “This is a new riddle.
Now I have it! What’s the difference between a tree and a bird? Can
you answer that?”
“Let me see now,” murmured Russ, who wanted to please his little
brother. “The difference between a bird and a tree. Well, one flies
and the other doesn’t.”
“Nope!” cried Laddie. “I’ll tell you. A tree leaves in the spring and a
bird leaves in the fall. See what I mean? A tree leaves in the spring
—the leaves come out. But a bird leaves in the fall. The bird leaves
the North and flies down South where it’s warm.”
“I don’t think that’s a very good riddle,” said Russ.
“Well, maybe I can think of a better one after a while,” Laddie
remarked cheerfully. He certainly was good-natured.
Now that the time of going to the farm had arrived, Violet was
eager to find out all about the animals. She fairly pestered Adam with
wanting to know things. She asked:
“How many chickens are there? How many cows? Did you ever
count the bees?”
“Count the bees? Good land, no!” laughed Adam. “There’s millions
of ’em and they never keep still long enough to be counted. Besides,
if I tried they might sting me.”
“Well,” said Vi, “are there any——”
“Violet, get in the truck and sit still,” ordered her mother firmly, and
Violet obeyed.
Everything was ready for the start. Mr. Bunker was counting the
children and the trunks and the satchels, to make sure none was
missing, when Rose asked:
“Where’s Margy?”
“Here she comes,” said Russ, as he noticed his little sister
appearing around the corner of the house.
“What in the world is she carrying?” asked Mr. Bunker.
And well might he inquire. For Margy was half dragging half
carrying a large pasteboard box which seemed alive, for it swayed
from side to side and seemed about to leap away.
“Margy, what have you there?” called her father.
Before she could answer the box gave a sudden lurch to one side,
Margy lost her balance, and down she went on the path in a heap,
the box tumbling over and over as if it had suddenly come to life.
What could it be?
CHAPTER VI
SOMETHING IN THE STRAW

Five little Bunkers, with their father, their mother, Norah, and Adam
North looked at one little Bunker in a queer plight. That one little
Bunker was Margy.
After her fall Margy rolled along the path a short distance, for she
was a round little girl, quite chubby and, as her father often said,
“about as broad as she was long.”
As Margy rolled along, the box she had been carrying also rolled.
There was nothing very strange in Margy’s rolling over and over
after a tumble. She often did that. So did the other little Bunkers. So,
also, do you if you are little and fat.
There was also nothing very strange in the box, which Margy had
been carrying, rolling over. That is, there would not have been
anything strange if the box had just rolled in one direction.
But it did not. It rolled this way and that way and the other way and
then it rolled this way again, in such a strange manner that Russ
cried:
“What in the world can be in that box to make it go that way?”
“It’s just as if it was alive!” said Rose.
“Maybe it’s a riddle!” suggested Laddie.
Mrs. Bunker had gone to Margy to pick her up. Beyond a scratch
or two and some bruises, together with some dust on her dress,
Margy was unharmed. She was used to cuts and bruises, so these
did not much matter. Nor did the dust.
Russ ran to pick up the queer, rolling box, calling out:
“What’s in it, Margy?”
Before she could answer there came from within the box, the
cover of which was fitted tightly on, a little yipping whine and bark.
“Oh, it’s a dog!” cried Mun Bun. “I want to see the dog!”
“Dog!” exclaimed Violet. “It must be a terribly little dog to be in a
box like that.”
“Margy, what have you in the box?” asked her father, as Russ was
trying to take off the cover.
“It’s a—now—a puppy!” answered Margy.
“A puppy!” cried the other five little Bunkers, while Margy’s mother
asked:
“Where did you get the puppy, Margy?”
“I went over to Tommy Baker’s house. His dog has some little
puppies, and I took one and put it in this box ’cause I want to take a
puppy with me to the farm,” Margy answered.
The others laughed.
By this time Russ had managed to get the cover off the box, and a
cute little puppy stuck his head out, and, with his tongue, began
licking Russ’s hands. I suppose that was the puppy’s way of telling
how glad he was to get out of the box.
“Oh, isn’t he sweet!” cried Rose.
“Could we keep him?” begged Violet.
“I love him an’ he’s my puppy!” announced Margy.
“Well, the next time you love a puppy don’t shut him up in a box
without any air, and don’t drop him so the box rolls and he turns
somersaults,” advised Daddy Bunker. “Russ, you run back to Mr.
Baker’s with the little dog, and tell him Margy didn’t really mean to
take it.”
“Oh, Daddy! can’t I keep it?” begged Margy.
“No, dear. It belongs to Tommy Baker. You’ll find animals enough
out at Farmer Joel’s, anyway,” said her mother, as Russ started back
with the puppy in his arms.
For a moment it seemed as if Margy would cry, but Mun Bun kept
her tears back by saying:
“It was awful funny when he did roll over and over in the box. I like
a puppy to do that!” And when the others laughed at Mun Bun’s
funny way of saying this, Margy also laughed.
Russ came running back, having left the puppy with the others, a
last look was taken around the house to see that all was in good
order, and then Mrs. Bunker and Norah started off in the touring car
and Daddy and Adam North started in the big straw-filled truck with
the six little Bunkers.
“Oh, this is great! It’s going to be lots of fun!” exclaimed Russ, as
they rumbled along.
“I hope there’s a big, old-fashioned kitchen at Farmer Joel’s,” said
Rose. “Mother said I might help her with the baking of cake and
pies.”
“Well, I’ll help with the eating,” laughed Russ. “I hope there’s a
brook on the farm. I want to make a water wheel and build a little toy
mill that the water wheel will turn.”
“I’ll help you,” offered Laddie, as Russ whistled merrily.
The way to Cedarhurst where Farmer Joel lived was along a
pleasant road, and the children, sitting on the straw in the big truck,
enjoyed looking out through openings in the canvas sides.
“Did we bring anything to eat?” asked Vi, after a few miles had
been journeyed.
“No, daddy said we were going to stop in Westfield for our lunch,”
explained Rose. “We are going to meet mother there and all eat
together in a restaurant.”
“Oh, that’ll be fun!” declared Vi.
“It would be more fun if we could camp beside the road, make a
fire and cook something,” suggested Russ.
“If I had a gun I could shoot something and we could cook that,”
cried Laddie.
“Pooh! What could you shoot? A bear?” asked his twin sister.
“No,” he drawled. “But maybe I could shoot a chicken.”
“If you did the farmer that owned it would have you arrested,”
declared Russ. “I guess it will be better for us to eat in the
restaurant.”
Adam North, who sat up in the front seat with Daddy Bunker,
suddenly turned the truck off to one side of the road and brought the
big machine to a stop.
“Oh, are we there already?” cried Rose, leaping up from the straw
where she had been sitting beside Russ.
“Are we at Farmer Joel’s?” asked Violet eagerly.
“I want to wide on a horsie!” demanded Mun Bun.
“No, we aren’t there yet,” answered Adam. “But I need some water
in the radiator of the auto, so I’ll just stop here and get some. There’s
a farmer here whom I know.”
“May we get out?” asked Russ, for he thought perhaps they might
not stop long enough for this.
“Oh, yes, get out and stretch your legs,” his father told him.
“I’ll wait here five or ten minutes and cool down the engine,” added
Adam.
With whoops and shouts of delight the six little Bunkers piled out
of the truck and ran up and down the road. The machine had come
to a stop with the open rear end close to a wooden platform, which
was just as high as the floor of the big car. From the platform a flight
of steps led to the ground, and the Bunker children got out on this
platform and so descended.
“What’s this for?” asked Violet, with her usual way of starting
questions.
“This,” her father told her, “is a milk platform.”
“What’s a milk——” began Vi, but her father held up his hand.
“I’ll tell you all about it, and then you won’t have to ask any more
questions,” he said, with a smile. “This platform is built for the farmer
to set his cans of milk on. It is made high, so it is easy to roll the
cans of milk from the platform into the wagon. The milk is collected
by a big wagon, or auto truck, from the cheese factory. Many farmers
around here sell their milk and cream to the cheese factory, and
these platforms are built to make the work easier.”
“Oh,” murmured Violet. She had never had so many questions
answered before without her asking any, and she was in rather a
daze.
“Now run along and play with the others,” her father told her, for
the five little Bunkers were wandering about, looking at things around
the farmhouse.
Mr. Armstrong owned the place, and he came out to shake hands
with Mr. Bunker and Adam North, telling the latter to take as much
water as he needed for the thirsty automobile.
Mrs. Armstrong invited the children in and gave them some
cookies and glasses of milk.
“Aren’t you afraid you’ll spoil your appetites for dinner by eating
now?” asked Daddy Bunker. “It’s eleven o’clock, and we’ll have lunch
about noon.”
“I guess I can eat again,” said Russ.
“So can I.” “And I!” cried the others.
“Bless their hearts!” laughed the motherly Mrs. Armstrong.
While the auto engine was cooling the children ran about and
played tag. Rose thought perhaps her mother and Norah might come
past in the touring car, but Adam said they had probably taken a
shorter way, over a back road.
“I couldn’t go that way because the truck is so heavy,” he
explained. “I have to stick to the hard highways. But we’ll meet your
mother in Westfield.”
“Oh, come on out and see what I found!” cried Margy, running
around the corner of the house.
“What is it?” asked Mun Bun.
“A lot of little pigs in a pen, and they squeal like anything!” Margy
answered.
“Oh, I want to see the pigs! Maybe I can make up a riddle about
’em!” cried Laddie.
There was a rush for the pen, and the children had fun watching
the little pigs stumble about, rooting with their pink noses in the dirt
of their pen for something to eat.
But now the engine was cool enough to travel on, and Mr. Bunker
called the children to come back. Russ was the first to reach the
machine, running up the platform steps ready to help his smaller
brothers and sisters if they needed it.
He peered inside the truck, thinking perhaps the straw would need
spreading out again in a smooth layer, and, as he did so, he started
back in surprise.
“What’s the matter?” asked Rose, who had followed him.
“There’s something in there—in the straw,” whispered Russ.
“You mean one of the children?” asked Rose, for thus she often
spoke of her smaller brothers and sister.
“No, it—it looks like some animal,” said Russ. “Look!”
Rose looked and saw a dark object—clearly an animal—moving
about in the straw.
“Oh, maybe it’s a bear!” she cried.
CHAPTER VII
AT FARMER JOEL’S

Four other little Bunkers were hurrying up the platform steps to get
into the auto truck when Rose and Russ made this discovery of a
strange animal in the straw.
The first impulse of Rose was to run from the animal that, she half
thought, might be a bear that had wandered in from the woods not
far away and had found the warm straw a good place in which to
sleep. The next thought Rose had was for her smaller brothers and
sisters.
Daddy Bunker and Adam North were up near the front of the truck,
getting ready to take their seats, for the engine was now cool and the
radiator filled with fresh water.
Russ had the same idea as had Rose—the desire to save his
brothers and sisters from harm. Seeing them coming up the platform
steps he cried:
“Keep back! Keep back! Don’t come up here!”
“What’s the matter?” asked Laddie.
“There’s something in the straw,” Russ answered.
“It’s an animal!” added Rose. “A big animal!”
“Oh, I want to see it!” cried Mun Bun. “I like animals! Maybe we
can have a circus—this is like a circus wagon!”
The big truck certainly was. But Rose did not intend to have Mun
Bun or the other small ones rush into danger. She stood on the milk
platform at the top of the steps, holding out her hands.
“You mustn’t go in there where the animal is!” cried Rose. “Russ,
can’t you do something?” and her voice was shrill with excitement.
“I’ll get a stick—a stone—something——” panted Russ.
Just then from inside the truck came a stamping sound, as if the
animal were kicking about. At the same time a loud cry echoed.
“What’s the matter?” asked Daddy Bunker, coming back from the
front end of the truck.
At the same time Mr. Armstrong, the farmer, hurried out of a side
gate, calling:
“Did any of you see a little colt? He got out of the pasture, and I
don’t want him to run away. He’s valuable and he may get hurt.”
Before any one could answer the sound of neighing came from
inside the truck, and then Russ knew it was made by the animal he
and Rose had seen standing in the straw.
“Ha! That sounds like my colt!” said Farmer Armstrong.
“It is!” shouted Russ, with a laugh. “He’s in the auto. I’ll get him
out.”
The oldest Bunker boy started to go inside the auto truck, whence
came the neighing, stamping sound of the little horse. But Mr.
Armstrong called out:
“No, lad, don’t go in there. He might kick you. Not that he’s ugly,
but he’s in a strange place, and if you go in he might think you meant
to harm him. Better let me do it. I know how to handle that colt.”
The six little Bunkers, with their father and Adam North, stood at
one side to allow Mr. Armstrong to enter the truck. In he went,
speaking soothing words to the little colt.
“Oh, ho, Bonnie Boy! So you thought you’d hide away and go with
the six little Bunkers, did you? None of that! We want you to stay on
our farm! So you tried to hide in the straw, did you, Bonnie Boy?
Well, come out and I’ll give you a lump of sugar.”
And out of the truck, onto the milk platform, walked Mr. Armstrong,
leading by his halter the colt Bonnie Boy, as he was named.
“Oh, isn’t he sweet?” cried Violet. “How old is he and where is his
mother and has he any brothers and sisters and——”
“Careful, Vi!” laughingly called her father. “Mr. Armstrong isn’t used
to having so many questions fired at him at once.”
“Oh, I don’t mind,” laughed the good-natured farmer. “But this is
the only little colt I have, and his mother is down in the south
pasture. Now you can pet him if you want to,” he added to the
children. “He won’t kick when he’s outside here where he can see
who is near him.”
Up on the platform, around Bonnie Boy, crowded the six little
Bunkers, and the colt rubbed his velvet-like nose against them and
whinnied softly.
“And to think I took him for a bear!” laughed Rose, as she stroked
the glossy neck of the colt.
“Well, he did look like one,” declared Russ.
“Did he walk up the steps?” asked Violet. “I don’t see how he
could.”
“Oh, he’s a great little colt,” said Mr. Armstrong proudly. “He does
all sorts of tricks. One day he got out of the pasture and walked right
into the kitchen where my wife was making a cake. She thought I
was coming in with my big boots on, so she didn’t turn around, and
the colt put his nose on the back of her neck. She—Ha! Ha! She
thought I was kissing her. Oh, ho! ho!” and the farmer laughed
heartily.
Then he led Bonnie Boy down the steps, the little colt making no
trouble at all about treading on them. He was taken back to the
pasture where his mother was waiting for him, doubtless wondering
what had become of him. It was found that there was a break in the
fence, just large enough for the colt to squeeze through, but not
large enough for his mother, or she would have followed him.
The colt had wandered about, coming up to the rear of the house,
and had then made his way to the front, going up the steps of the
milk platform, and so into the big straw-filled truck, which, perhaps,
he thought was a new kind of barn.
“Well, now we’d better be traveling,” said Mr. Bunker, when the
little colt was taken away. “We don’t want to be late in meeting
mother in Westfield.”
Once again the six little Bunkers were on their way.
They were soon at Westfield, a small country town, and when the
big truck drew up in front of the only restaurant in the place there
was the touring car, with Mrs. Bunker and Norah sitting in it, waiting.
“We got here first, and we would have been here before but I had
a puncture and we had to change a tire,” said Mrs. Bunker.
“That’s too bad,” remarked her husband.
“Did you have any adventures?” asked Mrs. Bunker.
“Oh, I should say we did!” cried Violet “There was——”
“The cutest little colt!” broke in Rose, “and he——”
“Was in the straw,” continued Russ, “and when Rose saw him she
——”
“Thought he was a bear,” said Laddie.
Thus several of the little Bunkers had a turn in telling what had
happened.
“That was quite an adventure!” laughed Mrs. Bunker, when she
had been told all that had taken place at the Armstrong farm.
“I’m trying to make up a riddle about the colt, but I haven’t got very
far yet,” said Laddie. “It’s something about straw and a horseshoe
and—oh, well, maybe I’ll think of it after a while,” he said hopefully.
They had a delightful time, lunching in the restaurant, and nothing
much happened except that Mun Bun spilled a glass of water in his
lap and got wet. But as it was a warm day it didn’t matter.
Margy discovered a little kitten wandering about the eating place,
and she insisted on giving pussy some of her milk. The result was,
Margy’s hands not being very steady, that she upset a glass of milk
on the floor.
But, as the restaurant keeper said, it didn’t matter, for the floor
needed mopping anyhow.
Once more the little party started off in the two automobiles, Mrs.
Bunker and Norah in the touring car taking the lead. In about an hour
more they were at Cedarhurst. Then very soon, turning down a quiet
country road, the six little Bunkers saw in the distance a white
farmhouse in the middle of broad fields—a farmhouse with barns
and other buildings around it.
“That’s a dandy place!” exclaimed Russ.
“Lovely,” murmured Rose.
“Is that where we’re going to stay?” asked Violet.
“Yes, that is Farmer Joel’s,” her father answered.
A little later the little Bunkers were fairly tumbling out of the auto
truck in their eagerness to see all the sights. Mrs. Bunker and Norah
were already at the place.
“My, but I’m glad to see you all!” cried Farmer Joel, and the six
little Bunkers needed but one look at him to make sure they would
love him, for Mr. Todd was a kindly man. And his sister, Miss Lavina,
was just as loving and kind.
“Well, I’m glad you’re here,” said Miss Todd. “Now that I see so
many lovely children it makes me want to stay and play with you. But
brother Joel says I need a vacation, so I’m going off on a visit.”
The big farm was the most delightful place in the world at which to
spend a vacation. As Adam North had said, there were broad fields
—some green pastures, and others where hay and grain were
growing. There were two orchards, one of apple trees and another of
peach trees.
“And don’t eat apples yet, for they aren’t ripe,” warned Farmer Joel
as the children, putting on their old clothes, started out to explore
things.
“I want to see some horses!” cried Laddie.
“I want to go where the sheep are,” Mun Bun said.
“So do I,” chimed in Margy.
“I’ll go to the kitchen to help mother,” offered Rose, but her mother
said:
“No, you run out and play now. Norah and I can manage the work
all right. Later on if you want to help you may.”
So Rose went out with Russ and the others.
“There’s a brook, Russ!” called Violet, as she caught sight of the
sparkle of a little stream.
“That’s good. Then I’ll make a water wheel and a mill,” said Russ.
He and Laddie were looking at the brook, poking in sticks to find
out how deep it was and making ready to build the dam for the water
wheel, when suddenly they heard the voice of Rose crying:
“Oh, drive him away! Make him go away! Oh! Oh! Oh!”
“What’s that?” asked Russ, looking up.
“It was Rose,” answered Laddie. “I guess——”
The loud barking of a dog interrupted him, and Rose cried again:
“Oh, Russ, come and drive him away!”
CHAPTER VIII
IN THE HAY

Russ looked up from the dam he was making for the water wheel.
He could not see Rose. Nor could Laddie, who was helping his
brother make the little mill pond. But Rose kept on yelling and the
dog kept on barking.
“Oh, somebody please come!” cried Rose.
“I’m coming!” shouted Russ.
He leaped up, followed by Laddie, and, as they turned around a
clump of bushes and looked down the brook they saw Rose standing
with her back against a big tree while in front of her, leaping about
and barking loudly, was a large brown dog.
“Oh, Russ! Russ!” begged his sister, as she caught sight of him
and Laddie. “Come and drive this dog away! He wants to bite me!”
“I’ll drive him away!” declared Russ.
“And I’ll help,” added Laddie. “He’s a bad dog!”
Before the two brothers could reach their sister there came
running toward Rose another boy. This boy had a freckled face and
red hair.
“Don’t hit my dog!” cried this red-haired boy. “He won’t hurt you.
Hi, Jimsie!” called this new boy, “behave yourself! Down! Quiet! Quit
your barking!”
The dog looked around at the voice, wagged his tail to show that
he was friendly, and stopped barking. Just then up rushed Russ and
Laddie with sticks in their hands. Rose also had a stick which she
had raised toward the dog, but she had not hit him.
“Don’t beat my dog Jimsie!” begged the strange boy. “He didn’t
mean any harm.”
“What did he try to bite my sister for?” demanded Russ, who was
angry.
“Oh, he didn’t exactly try to bite me,” said Rose. “He just barked a
lot and he wouldn’t let me get away, and I was afraid he’d bite me.”
“Jimsie wouldn’t bite anybody,” said the boy, whose name was
Ralph Watson. He lived on the farm next to that of Mr. Todd.
“Well, then, what made him bark at my sister?” asked Russ.
“’Cause she had a stick,” answered Ralph.
“Does he bark at everybody who has a stick?” asked Laddie. “If he
does why doesn’t he bark at Russ and me—we have sticks?”
“I guess he will bark at you as soon as he sees you have sticks,”
Ralph answered. “I’ll try him.” He moved around until he stood
beside Russ and Laddie, and as the dog’s eyes followed his young
master Jimsie caught sight of the two Bunker boys and the sticks
they held. At once Jimsie began to bark, greatly excited.
“There! I told you!” cried Ralph.
“What makes him bark so just because he sees a stick?” asked
Russ. “Does he think we’re going to hit him with ’em? I wouldn’t hit
any dog, unless he was going to bite somebody.”
“No, Jimsie doesn’t think he’s going to be hit,” explained Ralph.
“He just wants you to throw the sticks in the brook so he can jump in
and bring ’em out. Always when he sees any one with a stick he
thinks they’re going to play with him and throw the stick into the
water. I guess he thought you were going to play with him,” said
Ralph to Rose, “and when you didn’t—why, he just barked.”
“Oh, I see!” exclaimed Rose, with a laugh, for she was over her
fright now. “That was his way of asking me to throw the stick in the
water.”
“Yes,” answered Ralph with a smile that lighted up his jolly,
freckled face. “Sometimes he barks like anything when I take a stick
and don’t throw it in for him to bring out.”
And, indeed, Jimsie seemed very much excited now because
Russ and Laddie would not toss their sticks into the brook. And at
last, to please the dog, Russ tossed his stick in.
Instantly Jimsie plunged in after it, swimming out and bringing the
stick back to shore, dropping it at the feet of Russ as if asking that it
be thrown in again.
“Oh, isn’t he cute!” exclaimed Rose.
“He’s a good dog!” declared Russ.
“Will he bring out a stick for me?” asked Laddie.
“He’ll do it for anybody,” answered Ralph.
“I’ll try it,” said Laddie.
In he tossed his stick, and in plunged Jimsie after it, bringing it
back to shore, which made Laddie laugh. Then Jimsie gave himself
a shake, sending a shower of drops all over Rose, who was near
him.
“Oh!” cried the little Bunker girl in surprise.
“Jimsie, don’t you know any better than that?” cried Ralph, in a
scolding voice. “Shame on you!”
“Oh, I don’t mind,” said Rose quickly. “This is an old dress and
water won’t spot it. There, go in and get my stick!” she ordered, as
she tossed hers into the brook. “You wanted me to throw it before,
but I didn’t know what you meant by your barking. Now get the stick.”
Jimsie quickly brought the stick to shore for Rose. Then Ralph
tossed one in and his dog got that. Russ and Laddie wanted to try
their sticks over again, but Rose said:
“Oh, the poor dog will get tired! Don’t make him do so much.”
“He likes it,” Ralph said. “He’d chase sticks all day, I guess, if
you’d throw ’em for him. But maybe it’s time he quit. I have to go
after the cows, anyhow.”
“Where are they? Could we go with you?” asked Laddie eagerly.
“Do you live around here?” Russ wanted to know.
Ralph Watson told his name and where he lived, but he said it was
a long distance to the cow pasture where he had to go, and he
added that the mother of the Bunker children might not let them go.
“I’ll take you to-morrow if you want to come, though,” Ralph
promised.
“Then we’ll go,” said Rose.
Then, in answer to a question, she told the others that she had
been walking along the brook looking for watercress, of which Daddy
Bunker was very fond. Rose was using the stick to poke aside the
bushes on the edge of the brook when suddenly Jimsie had sprung
out at her, driving her back against the tree, where she had stood,
afraid to move while the dog barked so furiously.
“If I had only known he wanted to play I’d have played with him,”
finished Rose, with a laugh. “But I thought he was a savage dog.”
“Oh, Jimsie is never ugly,” said Ralph. “He barks a lot, but I guess
that’s because he has to do it when he helps me drive the cows.
Well, I’ll see you again,” he added, as he started away with his dog.
“He’s a nice boy,” said Rose, when he was out of sight.
“I’d like to have that dog,” remarked Russ.
“I think—now maybe—I guess I have a riddle about a dog,” began
Laddie, but before he could ask it, or even before he could think
what it was, yells and screams came from another part of the brook.
“That’s Mun Bun!” exclaimed Rose.
“Sounded like Margy, too,” said Russ.
“Maybe they’ve fallen into the water,” suggested Laddie.
Just then Violet was heard asking:
“Oh, what did you want to go and do that for? Now you have gone
and done it! Are your feet wet? Did you get hurt, Mun Bun?”

You might also like