<<

. 4
( 13)



>>

Plain also computes the values of several other dimension- in
bp
oriented values in addition to pt and mm , corresponding to the dimensions that cm
are understood by TEX. Here is the complete list: dd
cc
dimensions
pt printer™s point (72.27 pt = 1 in)
ad hoc dimensions
pc pica (1 pc = 12 pt) sharped
hash
in inch (1 in = 2.54 cm) sharped dimensions
bp big point (72 bp = 1 in) de¬ne pixels
hppp
cm centimeter (100 cm = 1 meter) de¬ne blacker pixels
mm millimeter (10 mm = 1 cm)
dd didot point (1157 dd = 1238 pt)
cc cicero (1 cc = 12 dd)
1
In each case the values are rounded to the nearest 65536 th of a pixel.
Although such standard physical dimensions are available, they haven™t
been used very much in traditional typefaces; designers usually specify other
units like ˜em ™ or ˜x height ™ in order to de¬ne the sizes of letters, and such
quantities generally have ad hoc values that vary from font to font. Plain -
makes it easy to introduce ad hoc dimensions that will vary with the
resolution and the magni¬cation just as pt and mm do; all you have to do is
de¬ne “sharped” dimensions that have the same name as your pixel-oriented
dimensions, but with ˜#™ tacked on as a su¬x. For example, em # and x height #
(typed ˜em#™ and ˜x_height#™ ) would be the sharped dimensions corresponding
has already de¬ned the quantities pt #,
to em and x height . Plain
pc #, in #, bp #, cm #, mm #, dd #, and cc # for the standard units named above.
Sharped dimensions like em # and x height # should always be de¬ned
in terms of resolution-independent dimension variables like pt #, in #, etc., so
that their values do not change in any way when mode and mag are varied.
The ˜#™ sign implies unchangeability. After mode setup has been called, the
pixel-oriented dimensions can be calculated by simply saying
de¬ne pixels(em , x height ).
This statement is an abbreviation for
em := em # — hppp ; x height := x height # — hppp
where hppp is an internal variable of that represents the number of
pixels per point in the horizontal dimension. Any number of ad hoc dimensions
can be listed in a single de¬ne pixels statement. Notice that ˜#™ is not an oper-
ator that could convert em to em #; rounding errors would be mode-dependent.
Chapter 5™s demonstration program io.mf contains several examples of
ad hoc dimensions de¬ned in this way, and it also contains the statement
de¬ne blacker pixels(thin , thick );
Chapter 11: Magni¬cation and Resolution 93


what™s this? Well, Appendix B makes that statement an abbreviation for blacker
proof
thin := thin # — hppp + blacker ; thick := thick # — hppp + blacker ; smoke
de¬ne corrected pixels
round
in other words, the sharped dimensions are being unsharped in this case by eps
converting them to pixels and then adding ˜blacker ™. The variable blacker is a o
o correction
special correction intended to help adapt a font to the idiosyncrasies of the cur- overshoot
rent output device; mode setup uses the value of mode to establish the value of ¬llin
corner
blacker . For example, cheapo mode might want blacker = 0.65, while luxo mode
might give best results when blacker = 0.1. The general convention is to add
blacker to pixel-oriented variables that determine the breadth of pens and the
thickness of stems, so that the letters will be slightly darker on machines that
otherwise would make them appear too light. Di¬erent machines treat pixels
quite di¬erently, because they are often based on quite di¬erent physical prin-
ciples. For example, the author once worked with an extremely high-resolution
device that tended to shrink stem lines rather drastically when it used a certain
type of photographic paper, and it was necessary to set blacker = 4 to get proper
results on that machine; another high-resolution device seems to want blacker
to be only 0.2. Experimentation is necessary to tune ™s output to
particular devices, but the author™s experience suggests strongly that such a cor-
rection is worthwhile. When mode = proof or smoke , the value of blacker is
taken to be zero, since the output in these modes is presumably undistorted.
EXERCISE 11.1
Does ˜mode = cheapo ; mag = 10™ produce exactly the same font as ˜mode =
luxo ™, under the assumptions of this chapter?
Line 7 of io.mf says ˜de¬ne corrected pixels(o)™, and this is yet a third
way of converting from true physical dimensions to pixel-oriented values. Ac-
cording to Appendix B, variable o is de¬ned by the assignment
o := round(o# — hppp — o correction ) + eps
where o correction , like blacker , is a magic number that depends on the output device
for which fonts are being made. On a high-resolution device like luxo , the appropriate
value for the o correction factor is 1; but on a low-resolution device like cheapo , the
author has obtained more satisfactory results with o correction = 0.4. The reason is
that ˜o™ is used to specify the number of pixels by which certain features of characters
“overshoot” the baseline or some other line to which they are visually related. High-
resolution curves look better when they overshoot in this way, but low-resolution curves
do not; therefore it is usually wise to curtail the amount of overshoot by applying the
o correction factor. In proof and smoke modes the factor is equal to 1.0, since these
modes correspond to high resolution.
The properties of output devices are modeled also by a parameter that™s called
¬llin , which represents the amount by which diagonal strokes tend to be darker
than horizontal or vertical strokes. More precisely, let us say that a “corner” pixel is
one whose color matches the color of ¬ve of its neighbors but not the other three,
where the three exceptions include one horizontal neighbor, one vertical neighbor, and
94 Chapter 11: Magni¬cation and Resolution


the diagonal neighbor between them. If a white corner pixel has apparent darkness f1 mode
and if a black corner pixel has apparent darkness 1 ’ f2 , then the ¬llin is f1 ’ f2 . (A mode def
proo¬ng
“true” raster image would have f1 = f2 = 0, but physical properties often cause pixels fontmaking
to in¬‚uence their neighbors.) tracingtitles
aspect ratio
Each output device for which you will be generating fonts should be repre- nonsquare
currenttransform
sented by a symbolic mode name in the implementation of that
you are using. Since these mode names vary from place to place, they are not standard
aspects of the language; for example, it is doubtful whether the hypotheti-
cal cheapo and luxo modes discussed in this chapter actually exist anywhere. The plain
base is intended to be extended to additional modes in a disciplined way,
as described at the end of Appendix B.
It™s easy to create a new symbolic mode, using plain ™s ˜mode def ™
convention. For example, the luxo mode we have been talking about could be
de¬ned by saying
mode def luxo =
pixels per inch := 2000; high res, almost 30 per point
%
blacker := .1; make pens a teeny bit blacker
%
o correction := 1; keep the full overshoot
%
¬llin := 0.1; compensate for darkened corners
%
proo¬ng := 0; no, we™re not making proofs
%
fontmaking := 1; yes, we are making a font
%
tracingtitles := 1; enddef ; yes, show titles online
%
The name of the mode should be a single symbolic token. The resolution should be
speci¬ed by assigning a value to pixels per inch ; all other dimension values (pt , mm ,
etc.) will be computed from this one by mode setup. A mode de¬nition should also
assign values to the internal variables blacker , o correction , and ¬llin (which describe
the device characteristics), as well as proo¬ng , fontmaking , and tracingtitles (which
a¬ect the amount of output that will be produced). In general, proo¬ng and fontmaking
are usually set to 0 and 1, respectively, in modes that are intended for font production
rather than initial font design; tracingtitles is usually 0 for low-resolution fonts (which
are generated quickly), but 1 for high-resolution fonts (which go more slowly), because
detailed online progress reports are desirable when comparatively long jobs are running.
Besides the seven mandatory quantities ˜pixels per inch ™, . . . , ˜tracingtitles ™
just discussed, a mode de¬nition might assign a value to ˜aspect ratio ™. In the
normal case when no aspect ratio is speci¬ed, it means that the fonts to be output are
assumed to have square pixels. But if, for example, the mode def sets aspect ratio :=
5/4, it means that the output pixels are assumed to be nonsquare in the ratio of 5
to 4; i.e., 5 vertical pixel units are equal to 4 horizontal pixel units. The pixel-oriented
dimensions of plain are given in terms of horizontal pixel units, so an aspect
ratio of 5/4 together with 2000 pixels per inch would mean that there are 2500 vertical
pixel units per inch; a square inch would consist of 2500 rows of pixels, with 2000 pixels
1 1
in each row. (Stating this another way, each pixel would be 2000 inches wide and 2500
will set the currenttransform variable
inches high.) In such a case, plain
so that all draw and ¬ll commands stretch the curves by a factor of 5/4 in the vertical
dimension; this compensates for the nonsquare pixels, so the typeface designer doesn™t
have to be aware of the fact that pixels aren™t square.
Chapter 11: Magni¬cation and Resolution 95


Let™s look now at a concrete example, so that it will be clear how the logo
parameter
ideas of device-independent font design can be implemented in practice. We
shall study a ¬le logo.mf that generates the seven letters of ™s logo.
There also are “parameter” ¬les logo10.mf, logo9.mf, etc., which use logo.mf
to produce fonts in various sizes. For example, a font containing the 10-point
characters ˜ ™ could be generated for the hypothetical luxo printer by
running with the command line
\mode=luxo; input logo10
if luxo mode really existed.
The main purpose of logo10.mf is to establish the “sharped” values of
several ad hoc dimensions; then it inputs logo.mf, which does the rest of the
work. Here is the entire ¬le logo10.mf:
% 10-point METAFONT logo
font_size 10pt#; % the "design size" of this font
ht#:=6pt#; % height of characters
xgap#:=0.6pt#; % horizontal adjustment
u#:=4/9pt#; % unit width
s#:=0; % extra space at the left and the right
o#:=1/9pt#; % overshoot
px#:=2/3pt#; % horizontal thickness of pen
input logo % now generate the font
end % and stop.
Similar ¬les logo9.mf and logo8.mf will produce 9-point ˜ ™ and
8-point ˜ ™; the letters get a little wider in relation to their height,
and the inter-character spacing gets signi¬cantly wider, as the size gets smaller:
% 9-point METAFONT logo % 8-point METAFONT logo
font_size 9pt#; font_size 8pt#;
ht#:=.9*6pt#; ht#:=.8*6pt#;
xgap#:=.9*0.6pt#; xgap#:=.8*0.6pt#;
u#:=.91*4/9pt#; u#:=.82*4/9pt#;
s#:=.08pt#; s#:=.2pt#;
o#:=1/10pt#; o#:=1/12pt#;
px#:=.9*2/3pt#; px#:=.8*2/3pt#;
input logo input logo
end end
It is interesting to compare the font generated by logo10.mf to the font gener-
ated by logo8.mf with mag=10/8: Both fonts will have the same values of ht ,
xgap , and px , when the magni¬cation has been taken into account. But the
magni¬ed 8-point font has a slightly larger value of u and a positive value of s ;
this changes ˜ ™ to ˜ ™.
96 Chapter 11: Magni¬cation and Resolution


Every font has a “design size,” which is a more-or-less arbitrary number that design size
TeX
re¬‚ects the size of type it is intended to blend with. Users of TEX select
at size
magni¬ed fonts in two ways, either by specifying an “at size” or by specifying a scale font size
factor (times 1000). For example, the 8-point logo can be used at 10/8 savepen
E
magni¬cation by referring either to ˜logo8 at 10pt™ or to ˜logo8 scaled 1250™ in a TEX
document. When an “at size” is speci¬ed, the amount of magni¬cation is the stated
size divided by the design size. A typeface designer can specify the design size by using
plain ™s ˜font size™ command as illustrated on the previous page. (If no
design size is speci¬ed, will set it to 128 pt, by default.)

The ¬le logo.mf itself begins by de¬ning three more ad hoc dimensions
in terms of the parameters that were set by the parameter ¬le; these dimensions
will be used in several of the programs for individual letters. Then logo.mf
makes the conversion to pixel units:
% Routines for the METAFONT logo
% (logo10.mf is a typical parameter file)
mode_setup;
ygap#:=(ht#/13.5u#)*xgap#; % vertical adjustment
leftstemloc#:=2.5u#+s#; % position of left stems
barheight#:=.45ht#; % height of bar lines
define_pixels(s,u,xgap,ygap,leftstemloc,barheight);
py#:=.9px#; define_blacker_pixels(px,py); % pen dimensions
pickup pencircle xscaled px yscaled py; logo_pen:=savepen;
define_corrected_pixels(o);

There™s nothing new here except the use of ˜savepen ™ in the second-last line;
this, as we will see in Chapter 16, makes the currently-picked-up pen available
for repeated use in the subsequent program.
After the initial de¬nitions just shown, logo.mf continues with programs
for each of the seven letters. For example, here is the program for ˜ ™, which
illustrates the use of u#, s#, ht #, leftstemloc , barheight , xgap , and logo pen :

beginchar("E",14u#+2s#,ht#,0);
pickup logo_pen;
x1=x2=x3=leftstemloc;
x4=x6=w-x1+o; x5=x4-xgap;
(Figure 11a will be inserted here;
y1=y6; y2=y5; y3=y4; too bad you can™t see it now.)

bot y1=0; top y3=h;
y2=barheight;
draw z6--z1--z3--z4; draw z2--z5;
labels(1,2,3,4,5,6);
endchar;

We have seen the essentials of the and the in Chapter 4; programs for the
other letters will appear later.
Chapter 11: Magni¬cation and Resolution 97


EXERCISE 11.2 F
M
The ad hoc dimensions ht #, xgap #, u#, s#, o#, and px # de¬ned in the parameter T
¬les all a¬ect the letter ˜ ™ de¬ned by this program. For each of these dimensions, kerning
kern
tell what would happen to the ˜ ™ if that dimension were increased slightly while ligtable
all the others stayed the same. font quad
font normal space
EXERCISE 11.3 font normal stretch
font normal shrink
Guess the program for ˜ ™ (which is almost the same as ˜ ™ ). =
:=
EXERCISE 11.4 ligtable
Write the complete programs for ˜ ™ and ˜ ™, based on the information in
Chapter 4, but using the style of the program for ˜ ™ above. The character widths
should be 18u# + 2s# and 13u# + 2s#, respectively.
The ¬le logo.mf also contains the following cryptic instructions, which cause
the letter pairs ˜ ™ and ˜ ™ to be typeset closer together than their bounding
boxes would imply:
ligtable "T": "A" kern -.5u#;
ligtable "F": "O" kern -u#;

Without these corrections ˜ ™ would be ˜ ™. Uppercase letters
are often subject to such spacing corrections, especially in logos; TEX will adjust the
spacing if the typeface designer has supplied ligtable information like this.
Finally, logo.mf closes with four more commands, which provide further in-
formation about how to typeset with this font:
font_quad 18u#+2s#;
font_normal_space 6u#+2s#;
font_normal_stretch 3u#;
font_normal_shrink 2u#;
A font quad is the unit of measure that a TEX user calls one ˜em™ when this font is
selected. The normal space, stretch, and shrink parameters de¬ne the interword spacing
when text is being typeset in this font. Actually a font like logo10 is rarely used to
typeset anything except the one word, ˜ ™; but the spacing parameters have
been included just in case somebody wants to typeset a sentence like ˜
™.
An optional ˜=™ or ˜:=™ sign may be typed after ˜font size™, ˜font quad™, etc.,
in case you think the ¬le looks better that way.
Notice that “sharped” units must be given in the ligtable kerning commands
and in the de¬nition of device-independent parameters like font size and
font quad. Appendix F discusses the complete rules of ligtable and other commands
by which programs can send important information to typesetting systems
like TEX. Adding these extra bits of information to a program after a font
has been designed is something like adding an index to a book after that book has been
written and proofread.
EXERCISE 11.5
What™s the longest English word that can be typeset with the font logo9?
98 Chapter 11: Magni¬cation and Resolution


Let™s summarize the general contents of logo.mf, now that we have seen it ligtable
font quad
all, because it provides an example of a complete typeface description (even
meta-font
though there are only seven letters): Assignments
magstep
The ¬le begins by de¬ning ad hoc dimensions and converting them to pixel
TeX
units, using mode setup, de¬ne pixels, etc.
Then come programs for individual letters. (These programs are often pre-
ceded by macro de¬nitions for subroutines that occur several times. For ex-
ample, we will see later that the ˜ ™ and the ˜ ™ of the logo are drawn with the
help of a subroutine that makes half of a superellipse; the de¬nition of this
macro actually comes near the beginning of logo.mf, just before the programs
for the letters.)
Finally there are special commands like ligtable and font quad, to de¬ne
parameters of the font that are helpful when typesetting.
The ¬le is accompanied by parameter ¬les that de¬ne ad hoc dimensions for
di¬erent incarnations of the typeface.
We could make lots of di¬erent parameter ¬les, which would produce lots of di¬erent
(but related) variations on the logo; thus, logo.mf de¬nes a “meta-font”
in the sense of Chapter 1.
EXERCISE 11.6
What changes would be necessary to generalize the logo routines so that the
bar-line height is not always 45 per cent of the character height?
Assignments ( ˜:=™ ) have been used instead of equations ( ˜=™ ) in the param-
eter ¬les logo10.mf, logo9.mf, and logo8.mf, as well as in the opening lines
of io.mf in Chapter 5; this contradicts the advice in Chapter 10, where we are told to
stick to equations unless assignments are absolutely necessary. The author has found
it convenient to develop the habit of using assignments whenever ad hoc dimensions
are being de¬ned, because he often makes experimental ¬les in which the ad hoc di-
mensions are changed several times. For example, it™s a good idea to test a particular
letter with respect to a variety of di¬erent parameter settings when that letter is ¬rst
being designed; such experiments can be done easily by copying the ad hoc parameter
de¬nitions from parameter ¬les into a test ¬le, provided that the parameters have been
de¬ned with assignments instead of equations.
TEX users have found it convenient to have fonts in a series of magni¬cations
that form a geometric series. A font is said to be scaled by ˜magstep 1™ if
it has been magni¬ed by 1.2; it is scaled by ˜magstep 2™ if it has been magni¬ed by
1.2 — 1.2 = 1.44; it is scaled by ˜magstep 3™ if it has been magni¬ed by 1.2 — 1.2 — 1.2 =
1.728; and so on. Thus, if a job uses a font that is scaled by magstep 2, and if that
entire job is magni¬ed by magstep 1, the font actually used for printing will be scaled
by magstep 3. The additive nature of magsteps makes it more likely that fonts will
exist at the desired sizes when jobs are magni¬ed. Plain supports this
convention by allowing constructions like
\mode=cheapo; mag=magstep 2; input logo9
logo for the cheapo printer, magni¬ed
if you want to generate the 9-point
by 1.44 (i.e., by magstep 2). You can also write ˜magstep 0.5™ for what TEX calls

˜\magstephalf™; this magni¬es by 1.2.
Chapter 11: Magni¬cation and Resolution 99


The sharped forms of dimensions are actually represented by plain - BURKITT
#™ turns out to be equal to 1. SWIFT
in terms of printer™s points, so that ˜pt
However, it is best for programmers not to make use of this fact; a program ought to
say, e.g., ˜em # := 10pt #™, even though the ˜pt #™ in this construction is redundant, and
even though the computer would run a few microseconds faster without it.
EXERCISE 11.7
Suppose you want to simulate a low-resolution printer on a high resolution
device; for concreteness, let™s say that luxo is supposed to produce the output of cheapo ,
with each black cheapo pixel replaced by a 10 — 10 square of black luxo pixels. Explain
how to do this to the logo10 font, by making appropriate changes to logo.mf. Your
output ¬le should be called cheaplogo10.2000gf.




A great Temptation must be withstood with great Resolution.
” WILLIAM BURKITT, Expository Notes on the New Testament (c. 1700)

What some invent, the rest enlarge.
” JONATHAN SWIFT, Journal of a Modern Lady (1729)
(page 100)




12
Boxes
Chapter 12: Boxes 101


Let™s pause now to take a closer look at the “bounding boxes” that enclose TeX
height
individual characters. In olden days, metal type was cast on a rectangular body baseline
in which each piece of type had the same vertical extent, although the type widths depth
width
would vary from character to character. Nowadays we are free of the mechanical reference point
constraints imposed by metal type, but the former metaphors are still useful: cmr10
cmsl10
A typesetting system like TEX imagines that each character ¬ts into a rectangular
box, and words are typeset by putting such boxes snugly next to each other.
The main di¬erence between the old conventions and the new ones is that
type boxes are now allowed to vary in height as well as in width. For example,
when TEX typesets ˜A line of type.™ it puts boxes together that essentially look
like this: ˜ ™. (The ˜A™ appears in a box ˜ ™ that sits on a given
baseline, while the ˜y™ appears in a box ˜ ™ that descends below the baseline.)
TEX never looks inside a box to see what character actually appears there; TEX™s
job is to put boxes together in the right places on a page, based only on the box
sizes. It is a typeface designer™s job to decide how big the boxes should be and
to create the characters inside the boxes.
Boxes are two-dimensional objects, but we ascribe three dimensions to
them because the vertical component is divided into two quantities, the height
(above the baseline) and the depth (below the baseline). The horizontal dimen-
sion is, of course, called the width. Here is a picture of a typical box, showing
its so-called reference point and baseline:

|
|
height
|
|

Baseline
Reference point’ •
’ ‘
depth

← width ’
’ ’
The example characters in previous chapters have all had zero depth, but we
will soon be seeing examples in which both height and depth are relevant.
A character shape need not ¬t inside the boundaries of its box. Indeed,
italic and slanted letters are put into ordinary boxes just as if they were not
slanted, so they frequently stick out at the right. For example, the letter ˜g™
in the font you are now reading (cmr10) can be compared with the ˜g™ in the
corresponding slanted font (cmsl10):

(A figure will be inserted here; too bad you can™t see it now.
It shows two g™s, as claimed. In fact, the same figure ap-
peared on page 63 of The TeXbook.)




The slanted ˜g™ has been drawn as if its box were skewed right at the top and
left at the bottom, keeping the baseline ¬xed; but TEX is told in both cases that
the box is 5 pt wide, 4.3055 pt high, and 1.9444 pt deep. Slanted letters will be
102 Chapter 12: Boxes


spaced properly in spite of the fact that their boxes have been straightened up, italic correction
beginchar
because the letters will match correctly at the baseline. sharped
w
Boxes also have a fourth dimension called the italic correction, which gives h
d
TEX additional information about whether or not a letter protrudes at the
graph paper
right. For example, the italic correction for an unslanted ˜g™ in cmr10 is 0.1389 pt, drift
while the corresponding slanted letter in cmsl10 has an italic correction of 0.8565 pt. endchar
The italic correction is added to a box™s width when math formulas like g2 or g 2 are
being typeset, and also in other cases as explained in The TEXbook.

Plain ™s beginchar command establishes the width, height,
and depth of a box. These dimensions should be given in terms of “sharped”
quantities that do not vary with the resolution or magni¬cation, because the size
of a character™s type box should not depend in any way on the device that will
be used to output that character. It is important to be able to de¬ne documents
that will not change even though the technology for printing those documents is
continually evolving. can be used to produce fonts for new devices
by introducing new “modes,” as we have seen in Chapter 11, but the new fonts
should still give the same box dimensions to each character. Then the device-
independent ¬les output by TEX will not have to be changed in any way when
they are printed or displayed with the help of new equipment.
The three dimensions in a beginchar command are given in reverse
alphabetical order: First comes the width, then the height, then the depth. The
beginchar routine converts these quantities into pixel units and assigns them
to the three variables w , h , and d . In fact, beginchar rounds these dimensions
to the nearest whole number of pixels; hence w, h, and d will always be integers.
™s pixels are like squares on graph paper, with pixel bound-
aries at points with integer coordinates. The left edge of the type box lies on
the line x = 0, and the right edge lies on the line x = w; we have y = h on the
top edge and y = ’d on the bottom edge. There are w pixels in each row and
h + d in each column, so there are exactly wh + wd pixels inside the type box.
Since w, h, and d are integers, they probably do not exactly match
the box dimensions that are assumed by device-independent typesetting systems
like TEX. Some characters will be a fraction of a pixel too wide; others will be a
fraction of a pixel too narrow. However, it™s still possible to obtain satisfactory
results if the pixel boxes are stacked together based on their w values and if the
accumulated error is removed in the spaces between words, provided that the box
positions do not drift too far away from their true device-independent locations.
A designer should strive to obtain letterforms that work well together when they
are placed together in boxes that are an integer number of pixels wide.
You might not like the value of w that beginchar computes by rounding the
device-independent width to the nearest pixel boundary. For example, you
might want to make the letter ˜m™ one pixel wider, at certain resolutions, so that its
three stems are equally spaced or so that it will go better with your ˜n™. In such a case
you can assign a new value to w, at any time between beginchar and endchar. This
Chapter 12: Boxes 103


new value will not a¬ect the device-independent box width assumed by TEX, but it dvi
parenthesis
should be respected by the software that typesets dvi ¬les using your font.
Computer Modern
meta-design
Here™s an example of a character that has nonzero width, height, and axis
depth; it™s the left parenthesis in Computer Modern fonts like cmr10. Computer ¬lldraw
soft
Modern typefaces are generated by programs that involve lots of pa- crisp
rameters, so this example also illustrates the principles of “meta-design”: Many
di¬erent varieties of left parentheses can be drawn by this one program. But
let™s focus our attention ¬rst on the comparatively simple way in which the box
dimensions are established and used, before looking into the details of how a
meta-parenthesis has actually been speci¬ed. (0,h) (w,h)
"Left parenthesis";
numeric ht #, dp #;
ht # = body height #; .5[ht #, ’dp #] = axis #;
beginchar ("(", 7u#, ht #, dp #);
italcorr ht # — slant ’ .5u#;
pickup ¬ne.nib ;
penpos1 (hair ’ ¬ne , 0); (Figure 12a will be
penpos2 (.75[thin , thick ] ’ ¬ne , 0); inserted here; too bad
you can™t see it now.)
penpos3 (hair ’ ¬ne , 0);
rt x1r = rt x3r = w ’ u; lft x2l = x1 ’ 4u;
top y1 = h; y2 = .5[y1 , y3 ] = axis ;
¬lldraw z1l {(z2l ’ z1l ) xscaled 3} . . . z2l
. . . {(z3l ’ z2l ) xscaled 3}z3l
- - z3r {(z2r ’ z3r ) xscaled 3} . . . z2r
. . . {(z1r ’ z2r ) xscaled 3}z1r - - cycle;
(0,’d) (w,’d)
penlabels(1, 2, 3); endchar;
The width of this left parenthesis is 7u#, where u# is an ad hoc pa-
rameter that ¬gures in all the widths of the Computer Modern characters. The
height and depth have been calculated in such a way that the top and bot-
tom of the bounding box are equally distant from an imaginary line called the
axis, which is important in mathematical typesetting. (For example, TEX puts
the bar line at the axis in fractions like 1 ; many symbols like ˜+™ and ˜=™,
2
as well as parentheses, are centered on the axis line.) Our example program
puts the axis midway between the top and bottom of the type by saying that
˜.5[ht #, ’dp #] = axis #™. We also place the top at position ˜ht # = body height #™ ;
here body height # is the height of the tallest characters in the entire typeface.
It turns out that body height # is exactly 7.5pt # in cmr10, and axis # = 2.5pt #;
hence dp # = 2.5pt #, and the parenthesis is exactly 10 pt tall.
The program for ˜(™ uses a ¬lldraw command, which we haven™t seen
before in this book; it™s basically a combination of ¬ll and draw, where the ¬lling
is done with the currently-picked-up pen. Some of the Computer Modern fonts
have characters with “soft” edges while others have “crisp” edges; the di¬erence
is due to the pen that is used to ¬lldraw the shapes. This pen is a circle whose
104 Chapter 12: Boxes


diameter is called ¬ne ; when ¬ne is fairly large, ¬lldraw will produce rounded ¬ne
hairline
corners, but when ¬ne = 0 (as it is in cmr10) the corners will be sharp. proof
The statement ˜penpos1 (hair ’¬ne , 0)™ makes the breadth of a simulated
broad-edge pen equal to hair ’ ¬ne at position 1; i.e., the distance between z1l
and z1r will be hair ’ ¬ne . We will be ¬lling a region between z1l and z1r with
a circle-shaped pen nib whose diameter is ¬ne ; the center of that nib will pass
through z1l and z1r , hence the pen will e¬ectively add 1 ¬ne to the breadth of
2
the stroke at either side. The overall breadth at position 1 will therefore be
2 ¬ne + (hair ’ ¬ne ) + 2 ¬ne = hair . (Computer Modern™s “hairline thickness”
1 1

parameter, which governs the breadth of the thinnest strokes, is called hair .)
Similarly, the statement ˜penpos2 (.75[thin , thick ] ’ ¬ne , 0)™ makes the overall
breadth of the pen at position 2 equal to .75[thin , thick ], which is 3 of the way
4
between two other parameters that govern stroke breadths in Computer Modern
routines. If ¬ne is increased while hair , thin , and thick stay the same, the e¬ect
will simply be to produce more rounded corners at positions 1 and 3, with little
or no e¬ect on the rest of the shape, provided that ¬ne doesn™t get so large that
it exceeds hair .
Here, for example, are ¬ve di¬erent left parentheses, drawn by our ex-
ample program with various settings of the parameters:
cmr10 cmbx10 cmvtt10 cmssdc10 cmti10




(Figure 12c will be in-
(Figure 12d will be
serted here; too bad (Figure 12e will be
(Figure 12a will be (Figure 12b will be in- inserted here; too
you can™t see it now.) inserted here; too
inserted here; too bad serted here; too bad you bad you can™t see it bad you can™t see it
you can™t see it now.) can™t see it now.) now.) now.)




u= 20 u= 23 u= 21 u= 19 u = 18.4
ht = 270 ht = 270 ht = 250 ht = 270 ht = 270
axis = 90 axis = 90 axis = 110 axis = 95 axis = 90
¬ne = 0 ¬ne = 0 ¬ne = 22 ¬ne = 8 ¬ne = 7
hair = 8 hair = 13 hair = 22 hair = 23 hair = 8
thin = 9 thin = 17 thin = 25 thin = 40 thin = 11
thick = 25 thick = 41 thick = 25 thick = 40 thick = 23
Parameter values are shown here in proof mode pixel units, 36 to the point.
Chapter 12: Boxes 105


(Thus, for example, the value of u# in cmr10 is 20 pt #.) Since cmbx10 is a “bold slanted
36
italic correction
extended” font, its unit width u is slightly larger than the unit width of cmr10, italcorr
and its pen widths (especially thick ) are signi¬cantly larger. The “variable- slant
width typewriter” font cmvtt10 has soft edges and strokes of almost uniform
thickness, because ¬ne and hair are almost as large as thin and thick . This font
also has a raised axis and a smaller height. An intermediate situation occurs
in cmssdc10, a “sans serif demibold condensed” font that is similar to the type
used in the chapter titles of this book; thick = thin in this font, but hairlines are
noticeably thinner, and ¬ne provides slightly rounded corners. The “text italic”
font cmti10 has rounded ends, and the character shape has been slanted by .25;
this means that each point (x, y) has been moved to position (x + .25y, y), in the
path that is ¬lled by ¬lldraw.
The vertical line just to the right of the italic left parenthesis shows the italic
correction of that character, i.e., the fourth box dimension mentioned earlier.
This quantity was de¬ned by the statement ˜italcorr ht # —slant ’.5u#™ in our program;
here slant is a parameter of Computer Modern that is zero in all the unslanted fonts,
but slant = .25 in the case of cmti10. The expression following italcorr should always
be given in sharped units. If the value is negative, the italic correction will be zero;
otherwise the italic correction will be the stated amount.
The author has obtained satisfactory results by making the italic correction
roughly equal to .5u plus the maximum amount by which the character sticks
out to the right of its box. For example, the top right end of the left parenthesis will be
nearly at position (w ’ u, ht ) before slanting, so its x coordinate after slanting will be
w ’ u + ht — slant ; this will be the rightmost point of the character, if we assume that
slant ≥ 0. Adding .5u, subtracting w, and rewriting in terms of sharped units gives the
stated formula. Notice that when slant = 0 the statement reduces to ˜italcorr ’.5u#™;
this means that unslanted left parentheses will have an italic correction of zero.
EXERCISE 12.1
Write a program for right parentheses, to go with these left parentheses.

The reader should bear in mind that the conventions of plain
and of Computer Modern are not hardwired into the language; they
are merely examples of how a person might use the system, and other typefaces
may well be better served by quite di¬erent approaches. Our program for left
parentheses makes use of beginchar, endchar, italcorr, penlabels, pickup,
penpos , lft , rt , top , z , and ¬lldraw, all of which are de¬ned somewhat arbitrarily
in Appendix B as part of the plain base; it also uses the quantities u , body height ,
axis , ¬ne , hair , thin , thick , and slant , all of which are arbitrary parameters that
the author decided to introduce in his programs for Computer Modern. Once
you understand how to use arbitrary conventions like these, you will be able to
modify them to suit your own purposes.
EXERCISE 12.2
(For people who know TEX.) It™s fairly clear that the width of a type box is
important for typesetting, but what use does TEX make of the height and depth?
106 Chapter 12: Boxes


The primitive commands by which actually learns the dimensions charwd
charht
of each box are rarely used directly, since they are intended to be embedded
chardp
in higher-level commands like beginchar and italcorr. But if you must know how charic
things are done at the low level, here is the secret: There are four internal quantities shipout
charcode
called charwd , charht , chardp , and charic , whose values at the time of every shipout location
command are assumed to be the box dimensions for the character being shipped out, in c code
charext
units of printer™s points. (See the de¬nitions of beginchar and italcorr in Appendix B
oriental
for examples of how these quantities can be manipulated.) chardx
dvi
Besides charwd and its cousins, also has four other internal vari- drift
ables whose values are recorded at the time of every shipout: w
charexists
charcode is rounded to the nearest integer and then converted to a number dangerous bend
between 0 and 255, by adding or subtracting multiples of 256 if necessary; this “c code”
is the location of the character within its font.
charext is rounded to the nearest integer; the resulting number is a secondary
code that can be used to distinguish between two or more characters with equal c codes.
(TEX ignores charext and assumes that each font contains at most 256 characters; but
extensions to TEX for oriental languages can use charext to handle much larger fonts.)
chardx and chardy represent horizontal and vertical escapement in units of
pixels. (Some typesetting systems use both of these device-dependent amounts to
change their current position on a page, just after typesetting each character. Other sys-
tems, like the dvi software associated with TEX, assume that chardy = 0 but use chardx
as the horizontal escapement whenever a horizontal movement by chardx does not cause
the subsequent position to drift too far from the device-independent position de¬ned by
accumulated charwd values. Plain ™s endchar routine keeps chardy = 0,
but sets chardx := w just before shipping a character to the output. This explains why
a change to w will a¬ect the spacing between adjacent letters, as discussed earlier.)
Two characters with the same c code should have the same box dimensions and
escapements; otherwise the second character will override the speci¬cations of
the ¬rst. The boolean expression ˜charexists c™ can be used to determine whether or
not a character with a particular c code has already been shipped out.
Let™s conclude this chapter by contemplating a program that gen-
erates the “dangerous bend” symbol, since that symbol appears so often in
this book. It™s a custom-made character intended to be used only at the very beginnings
of paragraphs in which the baselines of the text are exactly 11 pt apart. Therefore it
extends below its baseline by 11 pt; but it is put into a box of depth zero, because TEX
would otherwise think that the ¬rst line of the paragraph contains an extremely deep
character, and such depth would cause the second line to be moved down.
baselinedistance # := 11pt #; de¬ne pixels(baselinedistance );
heavyline # := 50/36pt #; de¬ne blacker pixels(heavyline );
beginchar (127, 25u#, h height # + border #, 0); "Dangerous bend symbol";
pickup pencircle scaled rulethickness ; top y1 = 25 h; lft x4 = 0;
27
x1 +x1 = x1a +x1b = x4b +x2a = x4 +x2 = x4a +x2b = x3b +x3a = x3 +x3 = w;
x4a = x4b = x4 + u; x3b = x1a = x1 ’ 2u;
y4 + y4 = y4a + y4b = y3b + y1a = y3 + y1 = y3a + y1b = y2b + y2a = y2 + y2 = 0;
2 4
y1a = y1b = y1 ’ 27 h; y4b = y2a = y4 + 27 h;
Chapter 12: Boxes 107


draw z1a . . z1 . . z1b - - - z2a . . z2 . . z2b - - - beginchar
location
z3a . . z3 . . z3b - - - z4a . . z4 . . z4b - - - cycle; % the signboard

x10 = x11 = x12 = x13 = .5w ’ u; x14 = x15 = x16 = x17 = w ’ x10 ; intersectionpoint
y10 = y14 = 28 h; bot y13 = ’baselinedistance ; HAGGARD
27
COLBURN
z11 = (z10 . . z13 ) intersectionpoint (z1a {z1a ’ z4b } . . z1 {right });
y15 = y11 ; y16 = y12 = ’y11 ; y17 = y20 = y21 = y13 ;
draw z11 - - z10 - - z14 - - z15 ; draw z12 - - z13 ; draw z16 - - z17 ; % the signpost
x20 = w ’ x21 ; x21 ’ x20 = 16u; draw z20 - - z21 ; % ground level
x36 = w ’ x31 ; x36 ’ x31 = 8u; x32 = x33 = x36 ; x31 = x34 = x35 ;
y31 = ’y36 = 12 h; y32 = ’y35 = 27 h; y33 = ’y34 = 27 h;
9 3
27
pickup pencircle scaled heavyline ;
draw z32 {z32 ’ z31 } . . z33 - - - z34 . . z35 {z36 ’ z35 }; % the dangerous bend
pickup penrazor xscaled heavyline rotated (angle(z32 ’ z31 ) + 90);
draw z31 - - z32 ; draw z35 - - z36 ; % upper and lower bars
labels(1a, 1b, 2a, 2b, 3a, 3b, 4a, 4b, range 1 thru 36); endchar;


This program has sev-
eral noteworthy points
of interest: (1) The ¬rst
parameter to beginchar
here is 127, not a string;
this puts the character
into font location 127.
(2) A sequence of equa-
tions like ˜a = w ’ b; a =
w ’ b ™ can conveniently
be shortened to ˜a + b =
a + b = w™. (3) Three
hyphens ˜- - -™ is an ab-
breviation for a line with
(Figure 12f will be inserted here; too bad you can™t see it now.)
“in¬nite” tension, i.e.,
an almost straight line
that connects smoothly
to its curved neighbors.
(4) An ˜intersectionpoint™
operation ¬nds out where
two paths cross; we™ll
learn more about this in
Chapter 14.


Well, we are in the same box.
” RIDER HAGGARD, Dawn (1884)

A story, too,
may be boxed.
” DOROTHY COLBURN, Newspaper Nomenclature (1927)
(page 108)




13
Drawing, Filling,
and Erasing
Chapter 13: Drawing, Filling, and Erasing 109


The pictures that produces are made up of tiny pixels that are either graph paper
¬ll
“on” or “o¬”; therefore you might imagine that the computer works behind the un¬ll
scenes with some sort of graph paper, and that it darkens some of the squares coordinates
whenever you tell it to draw a line or to ¬ll a region.
™s internal graph paper is actually more sophisticated than
this. Pixels aren™t simply “on” or “o¬” when is working on a picture;
they can be “doubly on” or “triply o¬.” Each pixel contains a small integer value,
and when a character is ¬nally shipped out to a font the black pixels are those
whose value is greater than zero. For example, the two commands
¬ll (0, 3) - - (9, 3) - - (9, 6) - - (0, 6) - - cycle;
¬ll (3, 0) - - (3, 9) - - (6, 9) - - (6, 0) - - cycle
yield the following 9 — 9 pattern of pixel values:
000111000
000111000
000111000
111222111
111222111
111222111
000111000
000111000
000111000

Pixels that have been ¬lled twice now have a value of 2.
When a simple region is “¬lled,” its pixel values are all increased by 1;
when it is “un¬lled,” they are all decreased by 1. The command
un¬ll (1, 4) - - (8, 4) - - (8, 5) - - (1, 5) - - cycle
will therefore change the pattern above to
000111000
000111000
000111000
111222111
100111001
111222111
000111000
000111000
000111000

The pixels in the center have not been erased (i.e., they will still be black if this
picture is output to a font), because they still have a positive value.
Incidentally, this example illustrates the fact that the edges between
™s pixels are lines that have integer coordinates, just as the squares
on graph paper do. For example, the lower left ˜0™ in the 9 — 9 array above
corresponds to the pixel whose boundary is ˜(0, 0) - - (1, 0) - - (1, 1) - - (0, 1) - -
cycle™. The (x, y) coordinates of the points inside this pixel lie between 0 and 1.
EXERCISE 13.1
What are the (x, y) coordinates of the four corners of the middle pixel in the
9 — 9 array?
EXERCISE 13.2
What picture would have been obtained if the un¬ll command had been given
before the two ¬ll commands in the examples above?
110 Chapter 13: Drawing, Filling, and Erasing


EXERCISE 13.3 doubly ¬lled
hole
Devise an un¬ll command that will produce the pixel values strange path
turning number
000111000
000101000
000101000
111212111
100101001
111212111
000101000
000101000
000111000

when it is used just after the ¬ll and un¬ll commands already given.
A “simple” region is one whose boundary does not intersect itself; more
complicated e¬ects occur when the boundary lines cross. For example,
¬ll (0, 1) - - (9, 1) - - (9, 4) - - (4, 4) - -
(4, 0) - - (6, 0) - - (6, 3) - - (8, 3) - - (8, 2) - - (0, 2) - - cycle
produces the pixel pattern
000011111
000011001
111122111
000011000

Notice that some pixels receive the value 2, because they™re “doubly ¬lled.”
There™s also a “hole” where the pixel values remain zero, even though they are
surrounded by ¬lled pixels; the pixels in that hole are not considered to be in
the region, but the doubly ¬lled pixels are considered to be in the region twice.
EXERCISE 13.4
Show that the ¬rst 9 — 9 cross pattern on the previous page can be generated
by a single ¬ll command. (The nine pixel values in the center should be 2, as if
two separate regions had been ¬lled, even though you are doing only one ¬ll.)
EXERCISE 13.5
What do you think is the result of ˜¬ll (0, 0) - - (1, 0) - - (1, 1) - - (0, 1) - - (0, 0) - -
(1, 0) - - (1, 1) - - (0, 1) - - cycle™ ?
A ¬ll command can produce even stranger e¬ects when its boundary
lines cross in only one place. If you say, for example,
¬ll (0, 2) - - (4, 2) - - (4, 4) - - (2, 4) - - (2, 0) - - (0, 0) - - cycle
will produce the 4 — 4 pattern
0011
0011
00
00

where ˜ ™ stands for the value ’1. Furthermore the machine will report that
you have a “strange path” whose “turning number” is zero! What does this
mean? Basically, it means that your path loops around on itself something like a
¬gure 8; this causes a breakdown in ™s usual rules for distinguishing
the “inside” and “outside” of a curve.
Chapter 13: Drawing, Filling, and Erasing 111


Every cyclic path has a turning number that can be understood as follows. digitized
Imagine that you are driving a car along the path and that you have a digital
compass that tells in what direction you™re heading. For example, if the path is
(0, 0) - - (2, 0) - - (2, 2) - - (0, 2) - - cycle
you begin driving in direction 0—¦ , then you make four left turns. After the ¬rst turn,
your compass heading is 90—¦ ; after the second, it is 180—¦ ; and after the third it is
270—¦ . (The compass direction increases when you turn left and decreases when you
turn right; therefore it now reads 270—¦ , not ’90—¦ .) At the end of this cycle the compass
will read 360—¦ , and if you go around again the reading will be 720—¦ . Similarly, if you
had traversed the path
(0, 0) - - (0, 2) - - (2, 2) - - (2, 0) - - cycle
(which is essentially the same, but in the opposite direction), your compass heading
would have started at 90—¦ and ended at ’270—¦ ; in this case each circuit would have
decreased the reading by 360—¦ . It is clear that a drive around any cyclic path will change
the compass heading by some multiple of 360—¦ , since you end in the same direction you
started. The turning number of a path is de¬ned to be t if the compass heading changes
by exactly t times 360—¦ when the path is traversed. Thus, the two example cycles we
have just discussed have turning numbers of +1 and ’1, respectively; and the “strange
path” on the previous page that produced both positive and negative pixel values does
indeed have a turning number of 0.
Here™s how actually implements a ¬ll command, assuming that
the cyclic path being ¬lled has a positive turning number: The path is ¬rst
“digitized,” if necessary, so that it lies entirely on the edges of pixels; in other words,
it is distorted slightly so that it is con¬ned to the lines between pixels on graph paper.
(Our examples so far in this chapter have not needed any such adjustments.) Then
each individual pixel value is increased by j and decreased by k if an in¬nite horizontal
line to the left of that pixel intersects the digitized path j times when the path is
traveling downward and k times when it is traveling upward. For example, let™s look
more closely at the non-simple path on the previous page that enclosed a hole:
¦
a¦b b¦b b b¦
a a a
a¦b c¦d¦
b¦c
a a a
¦e e¦f f ¦g
e e gg
a¦b
a a a bh hh
Pixel d has j = 2 descending edges and k = 1 ascending edges to its left, so its net
value increases by j ’ k = 1; pixels g are similar. Pixels c have j = k = 1, so they lie in
a “hole” that is un¬lled; pixels f have j = 2 and k = 0, so they are doubly ¬lled. This
rule works because, intuitively, the inside of a region lies at the left of a path whose
turning number is positive.
EXERCISE 13.6
True or false: When the turning number of a cyclic path is positive, a ¬ll
command increases each individual pixel value by l ’ m, if an in¬nite horizontal line to
the right of that pixel intersects the digitized path l times when the path is traveling
upward and m times when it is traveling downward. (For example, pixels e have l = 2
and m = 1; pixels c have l = m = 1.)
112 Chapter 13: Drawing, Filling, and Erasing


When the turning number is negative, a similar rule applies, except that the turningcheck
draw
pixel values are decreased by j and increased by k; in this case the inside of
penrazor
the region lies at the right of the path. ¬lldraw

But when the turning number is zero, the inside of the region lies sometimes at
the left, sometimes at the right. uses the rule for positive turning
number and reports that the path is “strange.” You can avoid this error message by
setting ˜turningcheck := 0™; in this case the rule for positive turning number is always
used for ¬lling, even when the turning number is negative.
Plain ™s draw command is di¬erent from ¬ll in two impor-
tant ways. First, it uses the currently-picked-up pen, thereby “thickening” the
path. Second, it does not require that the path be cyclic. There is also a third
di¬erence, which needs to be mentioned although it is not quite as important:
A draw command may increase the value of certain pixels by more than 1, even
if the shape being drawn is fairly simple. For example, the pixel pattern
0000000000000000000000000000000000000000000000000000000000000000000000
0000001111122222111110000000000000000000000000011111111000000000000000
0000111111111211111111100000000000000000000011111111111111000000000000
0001111111111011111111110000000000000000001111111111111111110000000000
0001111111111011111111110000000000000000111111111111111111111100000000
0011111111110001111111111000000000000001111111111111111111111110000000
0011111111110001111111111000000000000011111111111111111111111111000000
0011111111110001111111111000000000000111111111111111111111111111100000
0111111111100000111111111100000000001111111111111111111111111111110000
0111111111100000111111111100000000001111111111111111111111111111110000
0111111111100000111111111100000000011111111111111111111111111111111000
0111111111100000111111111100000000011111111111111111111111111111111000
0111111111100000111111111100000000111111111111111112111111111111111100
0111111111100000111111111100000000111111111111111112111111111111111100
0111111111100000111111111100000001111111111111111122111111111111111110
0111111111100000111111111100000001111111111111211121111211111111111110
0111111111100000111111111100000001111111111111112122221111111111111110
0111111111100000111111111100000001111111111111111100111111111111111110
0111111111100000111111111100000001111111111111112000011111111111111110
0111111111100000111111111100000001111111111112211000011211111111111110
0111111111100000111111111100000000111111111111110000001111111111111100
0111111111100000111111111100000000111111111111110000001111111111111100
0111111111100000111111111100000000011111111111100000000111111111111000
0111111111100000111111111100000000001111111111000000000011111111110000
0111111111100000111111111100000000000011111100000000000000111111000000
0000000000000000000000000000000000000000000000000000000000000000000000

was produced by two draw commands. The left-hand shape came from
pickup penrazor scaled 10; % a pen of width 10 and height 0
draw (6, 1){up } . . (13.5, 25) . . {down }(21, 1);
it™s not di¬cult to imagine why some of the top pixels get the value 2 here
because an actual razor-thin pen would cover those pixels twice as it follows the
given path. But the right-hand shape, which came from
pickup pencircle scaled 16; draw (41, 9) . . (51, 17) . . (61, 9)
is harder to explain; there seems to be no rhyme or reason to the pattern of 2™s
in that case. ™s method for drawing curves with thick pens is too
complicated to explain here, so we shall just regard it as a curious process that
occasionally shoots out extra spurts of ink in the interior of the shape that it™s
¬lling. Sometimes a pixel value even gets as high as 3 or more; but if we ignore
such anomalies and simply consider the set of pixels that receive a positive value,
we ¬nd that a reasonable shape has been drawn.
The left-parenthesis example in Chapter 12 illustrates the ¬lldraw com-
mand, which is like ¬ll in that it requires a cyclic path, and like draw in that it
Chapter 13: Drawing, Filling, and Erasing 113


uses the current pen. Pixel values are increased inside the region that you would drawdot
undraw
obtain by drawing the speci¬ed path with the current pen and then ¬lling in the un¬lldraw
interior. Some of the pixel values in this region may increase by 2 or more. The undrawdot
cullit
turning number of the path should be nonzero. culling
Besides ¬ll, draw, and ¬lldraw, you can also say ˜drawdot™, as il- erase
for
lustrated at the beginning of Chapter 5. In this case you should specify only cube
a single point; the currently-picked-up pen will be used to increase pixel values impossible cube
by 1 around that point. Chapter 24 explains that this gives slightly better results
than if you were to draw a one-point path.
There™s also an undraw command, analogous to un¬ll; it decreases pixel
values by the same amount that draw would increase them. Furthermore”
as you might expect”un¬lldraw and undrawdot are the respective opposites of
¬lldraw and drawdot.
If you try to use un¬ll and/or undraw in connection with ¬ll and/or draw,
you™ll soon discover that something else is necessary. Plain has
a cullit command that replaces all negative pixel values by 0 and all positive pixel
values by 1. This “culling” operation makes it possible to erase unwanted sections of
a picture in spite of the vagaries of draw and undraw, and in spite of the fact that
overlapping regions may be doubly ¬lled.
The command ˜erase ¬ll c™ is an abbreviation for ˜cullit; un¬ll c; cullit™;
this zeros out the pixel values inside the cyclic path c, and sets other pixel
values to 1 if they were positive before erasing took place. (It works because the initial
cullit makes all the values 0 or 1, then the un¬ll changes the values inside c to 0 or
negative. The ¬nal cullit gets rid of the negative values, so that they won™t detract
from future ¬lling and drawing.) You can also use ˜draw™, ˜¬lldraw™, or ˜drawdot™
with ˜erase™; for example, ˜erase draw p™ is an abbreviation for ˜cullit; undraw p;
cullit™, which uses the currently-picked-up pen as if it were an eraser applied to path p.
The cube at the right of this paragraph illustrates
one of the e¬ects that is easily obtained by erasing.
First the eight points are de¬ned, and the “back” square (Figure 13a will be in-
serted here; too bad you
is drawn; then two lines of the “front” square are erased, can™t see it now.)

using a somewhat thicker pen; ¬nally the remaining lines
are drawn with the ordinary pen:
s# := 5pt #; de¬ne pixels(s); % side of the square
z1 = (0, 0); z2 = (s, 0); z3 = (0, s); z4 = (s, s);
for k = 1 upto 4: zk+4 = zk + ( 2 s, 1 s); endfor
3 3
pickup pencircle scaled .4pt ; draw z5 - - z6 - - z8 - - z7 - - cycle;
pickup pencircle scaled 1.6pt ; erase draw z2 - - z4 - - z3 ;
pickup pencircle scaled .4pt ; draw z1 - - z2 - - z4 - - z3 - - cycle;
for k = 1 upto 4: draw zk - - zk+4 ; endfor.
At its true size the resulting cube looks like this: ˜ ™.
EXERCISE 13.7
Modify the draw-and-erase construction in the preceding paragraph so that
you get the impossible cube ˜ ™ instead.
114 Chapter 13: Drawing, Filling, and Erasing


EXERCISE 13.8 rotated
tension
Write a program to produce the symbol ˜ ™. [Hints: The char-
subpaths
acter is 10 pt wide, 7 pt high, and 2 pt deep. The starlike path can be de¬ned by ¬ve star
points connected by “tense” lines as follows: macro
overdraw
fullcircle
pair center ; center = (.5w, 2pt ); point
numeric radius ; radius = 5pt ; S
360 M¨bius
o
for k = 0 upto 4: zk = center + (radius , 0) rotated(90 + k); endfor
5
picture
def :: = . . tension 5 . . enddef ; currentpicture
path star ; star = z0 :: z2 :: z4 :: z1 :: z3 :: cycle;

You probably want to work with subpaths of star instead of drawing the whole path
at once, in order to give the illusion that the curves cross over and under each other.]

EXERCISE 13.9
What does the command ˜¬ll star ™ do, if star is the path de¬ned above?

EXERCISE 13.10
Devise a macro called ˜overdraw™ such that the command
˜overdraw c™ will erase the inside of region c and will then draw the
boundary of c with the currently-picked-up pen, assuming that c is a
cyclic path that doesn™t intersect itself. (Your macro could be used,
for example, in the program (Figure 13aa
will be inserted
here; too bad
path S; S = ((0, 1) . . (2, 0) . . (4, 2) . . you can™t see it
now.)
(2, 5.5) . . (0, 8) . . (2, 10) . . (3.5, 9)) scaled 9pt ;
for k = 0 upto 35: overdraw fullcircle scaled 3mm
shifted point k/35 — length S of S; endfor

to create the curious S shown here.)

EXERCISE 13.11
The M¨bius Watchband Corporation has a logo that looks like this:
o


(Figure 13bb will be inserted here; too bad you can™t see it now.)




Explain how to produce it (or something very similar) with .

Chapter 7 points out that variables can be of type ˜picture™, and Chapter 8
mentions that expressions can be of type ˜picture™, but we still haven™t seen
any examples of picture variables or picture expressions. Plain keeps the
currently-worked-on picture in a picture variable called currentpicture , and you can
copy it by equating it to a picture variable of your own. For example, if you say
˜picture v[ ]™ at the beginning of your program, you can write equations like

v1 = currentpicture ;

this makes v1 equal to the picture that has been drawn so far; i.e., it gives v1 the same
array of pixel values that currentpicture now has.
Chapter 13: Drawing, Filling, and Erasing 115


Pictures can be added or subtracted; for example, v1 +v2 stands for the picture sum of pictures
negative of a picture
whose pixel values are the sums of the pixel values of v1 and v2 . The “reverse-
inverse video
video dangerous bend” sign that heads this paragraph was made by substituting the reverse-video
following code for the ˜endchar™ in the program at the end of Chapter 12: dangerous bend
black/white reversal
nullpicture
picture dbend ; dbend = currentpicture ; clearit
endchar; % end of the normal dangerous bend sign beginchar
beginchar(0, 25u#, h height # + border #, 0); mode setup
picture primary
¬ll (0, ’11pt ) - - (w, ’11pt ) - - (w, h) - - (0, h) - - cycle; nullpicture
currentpicture := currentpicture ’ dbend ; (
)
endchar; % end of the reversed dangerous bend sign
picture secondary
picture tertiary
The pixel values in dbend are all zero or more; thus the pixels with a positive value, picture expression
after dbend has been subtracted from a ¬lled rectangle, will be those that are inside totalweight
epsilon
the rectangle but zero in dbend .

We will see in Chapter 15 that pictures can also be shifted, re¬‚ected, and
rotated by multiples of 90—¦ . For example, the statement ˜currentpicture :=
currentpicture shifted 3right ™ shifts the entire current picture three pixels to the right.

There™s a “constant” picture called nullpicture, whose pixel values are all
zero; plain de¬nes ˜clearit™ to be an abbreviation for the as-
signment ˜currentpicture :=nullpicture™. The current picture is cleared automatically
by every beginchar and mode setup command, so you usually don™t have to say
˜clearit™ in your own programs.

Here™s the formal syntax for picture expressions. Although has
comparatively few built-in operations that deal with entire pictures, the op-
erations that do exist have the same syntax as the similar operations we have seen
applied to numbers and pairs.

picture primary ’’ picture variable
| nullpicture
| ( picture expression )
| plus or minus picture primary
picture secondary ’’ picture primary
| picture secondary transformer
picture tertiary ’’ picture secondary
| picture tertiary plus or minus picture secondary
picture expression ’’ picture tertiary

The “total weight” of a picture is the sum of all its pixel values, divided by
65536; you can compute this numeric quantity by saying

totalweight picture primary .

divides by 65536 in order to avoid over¬‚ow in case of huge pictures. If the
totalweight function returns a number whose absolute value is less than .5, as it almost
always is, you can safely divide that number by epsilon to obtain the integer sum of
all pixel values (since epsilon = 1/65536).
116 Chapter 13: Drawing, Filling, and Erasing


Let™s turn to the computer again and try to evaluate some simple picture ex- hide
unitsquare
pressions interactively, using the general routine expr.mf of Chapter 8. When
edges
says ˜gimme™, you can type resolution

hide(fill unitsquare) currentpicture
and the machine will respond as follows:
>> Edge structure at line 5:
row 0: 0+ 1- |
What does this mean? Well, ˜hide™ is plain ™s sneaky way to insert a
command or sequence of commands into the middle of an expression; such commands
are executed before the rest of the expression is looked at. In this case the command
˜¬ll unitsquare ™ sets one pixel value of the current picture to 1, because unitsquare is
plain ™s abbreviation for the path (0, 0) - - (1, 0) - - (1, 1) - - (0, 1) - - cycle.
The value of currentpicture is displayed as ˜row 0: 0+ 1-™, because this means “in
row 0, the pixel value increases at x = 0 and decreases at x = 1.”
represents pictures internally by remembering only the vertical
edges where pixel values change. For example, the picture just displayed
has just two edges, both in row 0, i.e., both in the row between y coordinates 0 and 1.
(Row k contains vertical edges whose x coordinates are integers and whose y coordinates
run between k and k+1.) The fact that edges are represented, rather than entire arrays
of pixels, makes it possible for to operate e¬ciently at high resolutions,
because the number of edges in a picture is essentially proportional to the resolution
while the total number of pixels is proportional to the resolution squared. A ten-fold
increase in resolution therefore calls for only a ten-fold (rather than a hundred-fold)
increase in memory space and execution time.
Continuing our computer experiments, let™s declare a picture variable and ¬ll
a few more pixels:
hide(picture V; fill unitsquare scaled 2; V=currentpicture) V
11,
The resulting picture has pixel values and its edges are shown thus:
21

>> Edge structure at line 5:
row 1: 0+ 2- |
row 0: 0+ 2- 0+ 1- |
If we now type ˜-V™, the result is similar but with the signs changed:
>> Edge structure at line 5:
row 1: 0- 2+ |
row 0: 0- 2+ 0- 1+ |
(You should be doing the experiments as you read this.) A more interesting picture
transformation occurs if we ask for ˜V rotated-90™; the picture 2 1 appears below the
11
baseline, hence the following edges are shown:
>> Edge structure at line 5:
row -1: | 0++ 1- 2-
row -2: | 0+ 2-
Chapter 13: Drawing, Filling, and Erasing 117


Here ˜++™ denotes an edge where the weight increases by 2. The edges appear after ++
+++
vertical lines ˜|™ in this case, while they appeared before vertical lines in the previous
vertical line
examples; this means that has sorted the edges by their x coordinates. rotated
Each ¬ll or draw instruction contributes new edges to a picture, and unsorted edges shifted
edge structure
accumulate until needs to look at them in left-to-right order. (Type
V rotated-90 rotated 90
to see what V itself looks like when its edges have been sorted.) The expression
V+ V rotated 90 shifted 2right
produces an edge structure with both sorted and unsorted edges:
>> Edge structure at line 5:
row 1: 0+ 2- | 0+ 2-
row 0: 0+ 2- 0+ 1- | 0+ 1+ 2--
In general, addition of pictures is accomplished by simply combining the unsorted and
sorted edges of each row separately.
EXERCISE 13.12
Guess what will happen if you type ˜hide(cullit) currentpicture™ now; and
verify your guess by actually doing the experiment.
EXERCISE 13.13
Guess (and verify) what will happen when you type the expression
(V + V + V rotated 90 shifted 2right
- V rotated-90 shifted 2up) rotated 90.
[You must type this monstrous formula all on one line, even though it™s too long to ¬t
on a single line in this book.]
will complain that 45—¦ rotation is
If you ask for ˜V rotated 45™,
too hard. (Try it.) After all, square pixels can™t be rotated unless the angle
of rotation is a multiple of 90—¦ . On the other hand, ˜V scaled-1™ does work; you get
>> Edge structure at line 5:
row -1: 0- -2+ 0- -1+ |
row -2: 0- -2+ |
EXERCISE 13.14
Why is ˜V scaled-1™ di¬erent from ˜-V™ ?
EXERCISE 13.15
Experiment with ˜V shifted (1.5,3.14159)™ and explain what happens.
EXERCISE 13.16
Guess and verify the result of ˜V scaled 2™.
EXERCISE 13.17
Why does the machine always speak of an edge structure ˜at line 5™ ?
That completes our computer experiments. But before you log o¬, you might
want to try typing ˜totalweight V/epsilon™, just to verify that the sum of
all pixel values in V is 5.
118 Chapter 13: Drawing, Filling, and Erasing


The commands we have discussed so far in this chapter”¬ll, draw, ¬lldraw, picture command
addto command
un¬ll, etc.”are not really primitives of ; they are macros of plain
addto
, de¬ned in Appendix B. Let™s look now at the low-level operations on also
pictures that actually performs behind the scenes. Here is the syntax: addto
contour
picture command ’’ addto command | cull command addto
doublepath
addto command ’’ addto picture variable also picture expression with list
| addto picture variable contour path expression with list with clause
withpen
| addto picture variable doublepath path expression with list withweight
with list ’’ empty | with list with clause cull command
with clause ’’ withpen pen expression | withweight numeric expression cull
withweight
cull command ’’ cull picture variable keep or drop pair expression keep or drop
| cull command withweight numeric expression keeping
dropping
keep or drop ’’ keeping | dropping reverse-video
dangerous bend
The picture variable in these commands should contain a known picture; the com- currentpen
mand modi¬es that picture, and assigns the resulting new value to the variable. ¬ll
un¬ll
draw
The ¬rst form of addto command , ˜addto V also P ™, has essentially the
undraw
same meaning as ˜V := V + P ™. But the addto statement is more e¬cient, ¬lldraw
because it destroys the old value of V as it adds P ; this saves both time and space. un¬lldraw
envelope
Earlier in this chapter we discussed the reverse-video dangerous bend, which was said
to have been formed by the statement ˜currentpicture := currentpicture ’dbend ™. That
was a little white lie; the actual command was ˜addto currentpicture also ’dbend ™.
The details of the other forms of ˜addto™ are slightly more complex, but
(informally) they work like this, when V = currentpicture and q = currentpen :
Plain Corresponding primitives
¬ll c addto V contour c
contour c withweight ’1
un¬ll c addto V
draw p addto V doublepath p withpen q
doublepath p withpen q withweight ’1
undraw p addto V
¬lldraw c addto V contour c withpen q
contour c withpen q withweight ’1
un¬lldraw c addto V
The second form of addto command is ˜addto V contour p™, followed by
optional clauses that say either ˜withpen q™ or ˜withweight w™. In this case
p must be a cyclic path; each pen q must be known; and each weight w must be either
’3, ’2, ’1, +1, +2, or +3, when rounded to the nearest integer. If more than one
pen or weight is given, the last speci¬cation overrides all previous ones. If no pen is
given, the pen is assumed to be ˜nullpen™; if no weight is given, the weight is assumed
to be +1. Thus, the second form of addto command basically identi¬es a picture
variable V , a cyclic path p, a pen q, and a weight w; and it has the following meaning,
assuming that turningcheck is ¤ 0: If q is the null pen, path p is digitized and each
pixel value is increased by (j ’ k)w, where j and k are the respective numbers of
downward and upward path edges lying to the left of the pixel (as explained earlier in
this chapter). If q is not the null pen, the action is basically the same except that p
is converted to another path that “envelopes” p with respect to the shape of q; this
modi¬ed path is digitized and ¬lled as before. (The modi¬ed path may cross itself
Chapter 13: Drawing, Filling, and Erasing 119


in unusual ways, producing strange squirts of ink as illustrated earlier. But it will be convex
turningcheck
well behaved if path p de¬nes a convex region, i.e., if a car that drives counterclockwise
turning number
around p never turns toward the right at any time.) backwards path
strange path
If turningcheck > 0 when an ˜addto . . . contour™ command is being per- ¬lldraw
t
formed, the action is the same as just described, provided that path p has
ENE
a positive turning number. However, if p™s turning number is negative, the action compass directions
depends on whether or not pen q is simple or complex; a complex pen is one whose octants
NNE
boundary contains at least two points. If the turning number is negative and the pen is
NNW
simple, the weight w is changed to ’w. If the turning number is negative and the pen WNW
is complex, you get an error message about a “backwards path.” Finally, if the turning WSW
SSW
number is zero, you get an error message about a “strange path,” unless the pen is
simple and turningcheck <= 1. Plain sets turningcheck := 2; the ¬lldraw
macro in Appendix B avoids the “backwards path” error by explicitly reversing a path
whose turning number is negative.
We mentioned that the command ˜¬ll (0, 2) - - (4, 2) - - (4, 4) - - (2, 4) - -
(2, 0) - - (0, 0) - - cycle™ causes to complain about a strange path;
let™s take a closer look at the error message that you get:
> 0 ENE 1 NNE 2 (NNW WNW) WSW 3 SSW 4 WSW 5 (WNW NNW) NNE 0
! Strange path (turning number is zero).
What does this mean? The numbers represent “time” on the cyclic path, from the
starting point at time 0, to the next key point at time 1, and so on, ¬nally returning
to the starting point. Code names like ˜ENE™ stand for compass directions like “East
by North East”; decides in which of eight “octants” each part of a path
travels, and ENE stands for all directions between the angles 0—¦ and 45—¦ , inclusive. Thus,
this particular strange path starts in octant ENE at time 0, then it turns to octant NNE
after time 1. An octant name is parenthesized when the path turns through that
octant without moving; thus, for example, octants NNW and WNW are bypassed on the
way to octant WSW. It™s possible to compute the turning number from the given sequence
of octants; therefore, if you don™t think your path is really strange, the abbreviated
octant codes should reveal where has decided to take an unexpected turn.
(Chapter 27 explains more about strange paths.)
The third form of addto command is ˜addto V doublepath p™, followed
by optional clauses that de¬ne a pen q and a weight w as in the second case.
If p is not a cyclic path, this case reduces to the second case, with p replaced by the
doubled-up path ˜p & reverse p & cycle™ (unless p consists of only a single point, when
the new path is simply ˜p . . cycle™ ). On the other hand if p is a cyclic path, this
case reduces to two addto commands of the second type, in one of which p is reversed;
turningcheck is ignored during both of those commands.
An anomalous result may occur in the statement ˜draw p™ or, more generally,
in ˜addto V doublepath p withpen q™ when p is a very small cyclic path
and the current pen q is very large: Pixels that would be covered by the pen regardless
of where it is placed on p might retain their original value. If this unusual circumstance
hits you, the cure is simply to include the additional statement ˜draw z™ or ˜addto V
doublepath z withpen q™, where z is any point of p, since this will cover all of the
potentially uncovered pixels.
120 Chapter 13: Drawing, Filling, and Erasing


The cull command transforms a picture variable so that all of its pixel values cull
cullit
are either 0 or a speci¬ed weight w, where w is determined as in an addto
intersection
command. A pair of numbers (a, b) is given, where a must be less than or equal union
to b. To cull “keeping (a, b)” means that each new pixel value is w if and only if the symmetric di¬erence
selective complement
corresponding old pixel value v was included in the range a ¤ v ¤ b; to cull “dropping xor
(a, b)” means that each new pixel value is w if and only if the corresponding old pixel
value v was not in that range. Thus, for example, ˜cullit™ is an abbreviation for
cull currentpicture keeping (1, in¬nity )
or for
cull currentpicture dropping (’in¬nity , 0)
(which both mean the same thing). A more complicated example is
cull V5 dropping (’3, 2) withweight ’2;
this changes the pixel values of V5 to ’2 if they were ’4 or less, or if they were 3
or more; pixel values between ’3 and +2, inclusive, are zeroed.
A cull command must not change pixel values from zero to nonzero. For
example, doesn™t let you say ˜cull V1 keeping (0, 0)™, since that
would give a value of 1 to in¬nitely many pixels.
EXERCISE 13.18
What is the e¬ect of the following sequence of commands?
picture V [ ];
V1 = V2 = currentpicture ;
cull V1 dropping (0, 0);
cull V2 dropping (’1, 1);
currentpicture := V1 ’ V2 ;
EXERCISE 13.19
Given two picture variables V1 and V2 , all of whose pixel values are known to
be either 0 or 1, explain how to replace V1 by (a) V1 © V2 ; (b) V1 ∪ V2 ; (c) V1 • V2 .
[The intersection V1 © V2 has 1™s where V1 and V2 both are 1; the union V1 ∪ V2 has 0™s
where V1 and V2 both are 0; the symmetric di¬erence or selective complement V1 • V2
has 1™s where V1 and V2 are unequal.]
EXERCISE 13.20
Explain how to test whether or not two picture variables are equal.
EXERCISE 13.21
Look at the de¬nitions of ¬ll, draw, etc., in Appendix B and determine the
e¬ect of the following statements:
a) draw p withpen q;
b) draw p withweight 3;
c) undraw p withweight w;
¬ll c withweight ’2 withpen q;
d)
erase ¬ll c withweight 2 withpen currentpen ;
e)
f) cullit withweight 2.
Chapter 13: Drawing, Filling, and Erasing 121


EXERCISE 13.22 safe¬ll
strange path
Devise a safe¬ll macro such that ˜safe¬ll c™ increases the pixel values of
outline
currentpicture by 1 in all pixels whose value would be changed by the command ˜¬ll c™. Conway
(Unlike ¬ll, the safe¬ll command never stops with a “strange path” error; furthermore, Life
SWIFT
it never increases a pixel value by more than 1, nor does it decrease any pixel values, SUTHERLAND
even when the cycle c is quite wild.)
EXERCISE 13.23
Explain how to replace a character by its “outline”: All black pixels whose
four closest neighbors are also black should be changed to white, because they are in
the interior. (Diagonally adjacent neighbors don™t count.)
EXERCISE 13.24
In John Conway™s “Game of Life,” pixels are said to be either alive or dead.
Each pixel is in contact with eight neighbors. The live pixels in the (n + 1)st generation
are those who were dead and had exactly three live neighbors in the nth generation, or
those who were alive and had exactly two or three live neighbors in the nth generation.
Write a short program that displays successive generations on your screen.




Blot out, correct, insert, re¬ne,
Enlarge, diminish, interline;
Be mindful, when Invention fails,
To scratch your Head, and bite your Nails.
” JONATHAN SWIFT, On Poetry: A Rapsody (1733)

The understanding that can be gained from computer drawings
is more valuable than mere production.
” IVAN E. SUTHERLAND, Sketchpad (1963)
(page 122)




14
Paths
Chapter 14: Paths 123


The boundaries of regions to be ¬lled, and the trajectories of moving pens, are boundaries
trajectories
“paths” that can be speci¬ed by the general methods introduced in Chapter 3. paths
allows variables and expressions to be of type path, so that a de- quartercircle
circle
signer can build new paths from old ones in many ways. Our purpose in this halfcircle
chapter will be to complete what Chapter 3 began; we shall look ¬rst at some fullcircle
ellipse
special features of plain that facilitate the creation of paths, then we
shall go into the details of everything that knows about pathmaking.
A few handy paths have been prede¬ned in Appendix B as part of plain
, because they turn out to be useful in a variety of applications.

<<

. 4
( 13)



>>