0.65 while luxo mode has blacker = 0.1 (since the luxo printer has di¬erent physi- Tobin

cal characteristics). Similarly, de¬ne corrected pixels (which we are just about to

discuss) will produce slightly di¬erent results in the two given modes.

11.2. Increasing ht # would make the letter shape and the bounding box taller;

increasing xgap # would move point 5 to the left, thereby making the middle bar shorter;

increasing u# would make the shape and its bounding box wider; increasing s# would

widen the bounding box at both sides without changing the letter shape; increasing o#

would move points 4, 5, and 6 to the right; increasing px # would make the pen thicker

(preserving the top edge of the upper bar, the bottom edge of the lower bar, and the

center of the middle bar and the stem).

11.3. The only possible surprise is the position of y1 , which should match similar

details in the ˜ ™ and the ˜ ™ of Chapter 4:

beginchar("F",14*u#+2s#,ht#,0); pickup logo_pen;

x1=x2=x3=leftstemloc; x4=w-x1+o; x5=x4-xgap;

y2=y5; y3=y4; bot y1=-o; top y3=h; y2=barheight;

draw z1--z3--z4; draw z2--z5;

labels(1,2,3,4,5); endchar;

11.4. The quantity called ss in Chapter 4 is now leftstemloc .

beginchar("M",18*u#+2s#,ht#,0); pickup logo_pen;

x1=x2=leftstemloc; x4=x5=w-x1; x3=w-x3;

y1=y5; y2=y4; bot y1=-o; top y2=h+o; y3=y1+ygap;

draw z1--z2--z3--z4--z5;

labels(1,2,3,4,5); endchar;

beginchar("T",13*u#+2s#,ht#,0); pickup logo_pen;

lft x1=0; x2=w-x1; x3=x4=.5w;

y1=y2=y3; top y1=h; bot y4=-o;

draw z1--z2; draw z3--z4;

labels(1,2,3,4); endchar;

11.5. ˜ ™; possibly also ˜ ™; and Georgia Tobin sug-

gests that ˜ ™ might be a legal term.

11.6. Delete the line of logo.mf that de¬nes barheight#, and insert that line into

each of the parameter ¬les logo10.mf, logo9.mf, logo8.mf. Then other bar-line heights

are possible by providing new parameter ¬les; another degree of “meta-ness” has there-

fore been added to the meta-font.

11.7. (This is tricky.) Insert the lines

if known pixmag: begingroup interim hppp:=pixmag*hppp;

special "title cheapo simulation" endgroup;

extra_endchar:="currentpicture:=currentpicture scaled pixmag;"

& "w:=w*pixmag;" & extra_endchar; fi

right after ˜mode_setup™ in logo.mf, and also include the line

if known pixmag: hppp:=pixmag*hppp; vppp:=pixmag*vppp; fi

Appendix A: Answers to All the Exercises 241

at the very end of that ¬le. Then run with special

gf

\mode="cheapo"; input cheaplogo10

where the ¬le ˜cheaplogo10.mf™ says simply ˜pixmag=10; input logo10™. (The interim

hppp setting and the special command are used to fool into giving the

appropriate extension to the gf ¬le name. Incidentally, you could print with this font on

cheapo at ten-fold magni¬cation if you told TEX to use the font ˜cheaplogo10 scaled

10000™; but on luxo you would simply call this font ˜cheaplogo10™.)

12.1. The changes are straightforward, except for the italic correction (for which a

rough estimate like the one shown here is good enough):

"Right parenthesis";

numeric ht #, dp #; ht # = body height #; .5[ht #, ’dp #] = axis #;

beginchar (")", 7u#, ht #, dp #); italcorr axis # — slant ’ .5u#;

pickup ¬ne.nib ; penpos1 (hair ’ ¬ne , 0);

penpos2 (.75[thin , thick ] ’ ¬ne , 0); penpos3 (hair ’ ¬ne , 0);

lft x1l = lft x3l = u; rt x2r = 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;

penlabels(1, 2, 3); endchar;

We will see in Chapter 15 that it™s possible to guarantee perfect symmetry between left

and right parentheses by using picture transformations.

12.2. When horizontal lines are being typeset, TEX keeps track of the maximum

height and maximum depth of all boxes on the line; this determines whether or not

extra space is needed between baselines. The height and depth are also used to position

an accent above or below a character, and to place symbols in mathematical formulas.

Sometimes boxes are also stacked up vertically, in which case their heights and depths

are just as important as their widths are for horizontal setting.

13.1. (4, 4), (4, 5), (5, 5), (5, 4). (Therefore the command

un¬ll (4, 4) - - (4, 5) - - (5, 5) - - (5, 4) - - cycle

will decrease the value of this pixel by 1.)

13.2. The result would be exactly the same; ¬ll and un¬ll commands can be given

in any order. (After an initial un¬ll command, some pixel values will be ’1, the

others will be zero.)

13.3. un¬ll (4, 1) - - (4, 8) - - (5, 8) - - (5, 1) - - cycle.

13.4. Here are two of the many solutions:

¬ll (0, 3) - - (9, 3) - - (9, 6) - - (6, 6) - - (6, 9) - -

(3, 9) - - (3, 0) - - (6, 0) - - (6, 6) - - (0, 6) - - cycle;

¬ll (0, 3) - - (9, 3) - - (9, 6) - - (0, 6) - - (0, 3) - -

(3, 3) - - (3, 0) - - (6, 0) - - (6, 9) - - (3, 9) - - (3, 3) - - cycle.

(It turns out that any pixel pattern can be obtained by a single, su¬ciently hairy ¬ll

command. But unnatural commands are usually also ine¬cient and unreadable.)

242 Appendix A: Answers to All the Exercises

13.5. The value of the enclosed pixel is increased by 2. (We™ll see later that there™s cullit

undraw

a simpler way to do this.)

withpen

clearit

13.6. True; j ’ k = l ’ m, since k + l = j + m. (What comes up must go down.) withpen

addto

13.7. The tricky part is to remember that ˜erase draw zi - - zj ™ will erase pixels withweight

undraw

near zi and zj . Therefore if z3 - - z4 is drawn before z4 - - z2 , we can™t erase z4 - - z2

cullit

without losing some of z3 - - z4 ; it™s necessary to erase only part of one line. One way undraw

Leban

to solve the problem is to do the following, after de¬ning the points and picking up the

pen as before:

draw z3 - - z4 ; draw z5 - - z6 ;

cullit; pickup pencircle scaled 1.6pt ;

undraw z7 - - 1 [z7 , z5 ]; undraw z2 - - 1 [z2 , z4 ];

2 2

cullit; pickup pencircle scaled .4pt ;

draw z3 - - z1 - - z2 - - z4 ; draw z5 - - z7 - - z8 - - z6 ;

for k = 1 upto 4: draw zk - - zk+4 ; endfor.

(Note that it would not be quite enough to erase only from z7 to 1 [z7 , z5 ]!)

3

It™s also possible to solve this problem without partial erasing, if we use addi-

tional features of that haven™t been explained yet. Let™s consider only the

job of drawing z7 - - z5 - - z6 and z3 - - z4 - - z2 , since the other eight lines can easily be

added later. Alternative Solution 1 uses picture operations:

pen eraser ; eraser = pencircle scaled 1.6pt ;

draw z3 - - z4 ; erase draw z7 - - z5 withpen eraser ; draw z7 - - z5 ;

picture savedpicture ; savedpicture = currentpicture ; clearit;

draw z6 - - z5 ; erase draw z2 - - z4 withpen eraser ; draw z2 - - z4 ;

addto currentpicture also savedpicture .

Alternative Solution 2 is trickier, but still instructive; it uses ˜withweight™ options and

the fact that draw does not increase any pixel values by more than the stated weight

when the path is a straight line:

- - z4 ; undraw z7 - - z5 withpen eraser ;

draw z3

draw z7 - - z5 withweight 2; cullit withweight 2;

- - z5 ; undraw z2 - - z4 withpen eraser ;

draw z6

draw z2 - - z4 withweight 2;

(These alternative solutions were suggested by Bruce Leban.)

13.8. Here™s an analog of the ¬rst solution to the previous exercise:

beginchar ("*", 10pt #, 7pt #, 2pt #);

pair center ; . . . as in the hint

pickup pencircle scaled .4pt ; draw star ;

cullit; pickup pencircle scaled 1.6pt ;

for k = 0 upto 4: undraw subpath(k + .55, k + .7) of star ; endfor

cullit; pickup pencircle scaled .4pt ;

for k = 0 upto 4: draw subpath(k + .47, k + .8) of star ; endfor

labels(0,1,2,3,4); endchar.

Appendix A: Answers to All the Exercises 243

However, as in the previous case, there™s an Alternate Solution 1 by Bruce Leban that Leban

overdraw

is preferable because it doesn™t depend on magic constants like .55 and .47:

begingroup

interim

beginchar . . . as above . . . scaled .4pt ; addto

picture savedpicture ; savedpicture = nullpicture; cull

cullit

pen eraser ; eraser := pencircle scaled 1.6pt ; also

for k = 0 upto 4: endgroup

origin

draw subpath(k, k + 1) of star ; cullit;

undraw subpath(k + 3, k + 4) of star withpen eraser ; cullit;

addto savedpicture also currentpicture ; clearit; endfor

currentpicture := savedpicture ; labels(0,1,2,3,4); endchar.

13.9. It increases pixel values by 1 in the ¬ve lobes of the star, and by 2 in the

central pentagon-like region.

13.10. def overdraw expr c = erase ¬ll c; draw c enddef .

13.11. First we need to generalize the overdraw macro of the previous exercise so

that it applies to arbitrary cycles c, even those that are self-intersecting:

def overdraw expr c = begingroup

picture region ; region := nullpicture;

interim turningcheck := 0; addto region contour c;

cull region dropping (0, 0);

cullit; addto currentpicture also ’region ; cullit;

draw c endgroup enddef ;

(This code uses operations de¬ned later in this chapter; it erases the region of pixels

that would be made nonzero by the command ˜¬ll c™.) The watchband is now formed

by overdrawing its links, one at a time, doing ¬rst the ones that are underneath:

beginchar(M , 1.25in #, .5in #, 0); pickup pencircle scaled .4pt ;

z1 = (20, ’13); z2 = (30, ’6); z3 = (20, 1); z4 = (4, ’7);

z5 = (’12, ’13); z6 = (’24, ’4); z7 = (’15, 6);

path M ; M = (origin . . z1 . . z2 . . z3 . . z4 . . z5 . . z6 . . z7 . .

origin . . ’z7 . . ’z6 . . ’z5 . . ’z4 . . ’z3 . . ’z2 . . ’z1 . . cycle)

scaled (h/26) shifted (.5w, .5h);

def link(expr n) =

overdraw subpath 1 (n, n + 1) of M - -

3

subpath 1 (n + 25, n + 24) of M - - cycle enddef ;

3

for k = 1 upto 12: link(k + 11); link(12 ’ k); endfor endchar;

13.12. The pixel pattern 1 1 is culled to 11, and needs to sort the edges

21 11

as it does this; so the result is simply

row 1: | 0+ 2-

row 0: | 0+ 2-

13.13. The pixel pattern is 1 1 + 1 1 + 1 1 ’ 2 1 = 1 2 before the ¬nal rotation, with

21 21 12 11 43

the reference point at the lower left corner of the 4; after rotation it is 2 3 , with the

14

reference point at the lower right corner of the 4. Rotation causes to sort

244 Appendix A: Answers to All the Exercises

the edges, but the transition values per edge are never more than ±3. You weren™t xscaled-1

expected to know about this limit of ±3, but it accounts for what is actually reported: yscaled-1

save

interim

row 1: | -2++ -1+ 0---

turningcheck

row 0: | -2+ -1+++ 0--- 0-

13.14. ˜V scaled-1™ should be the same as ˜V rotated 180™, because transformations

apply to coordinates rather than to pixel values. (Note, incidentally, that the re¬‚ections

˜V xscaled-1™ and ˜V yscaled-1™ both work, and that ˜V scaled-1™ is the same as

˜V xscaled-1 yscaled-1™.)

13.15. The result is the same as ˜V shifted (2,3)™; the coordinates of a shift are

rounded to the nearest integers when a picture is being shifted.

13.16. row 3: 0+ 4- |

row 2: 0+ 4- |

row 1: 0+ 4- 0+ 2- |

row 0: 0+ 4- 0+ 2- |

(Scaling of pictures must be by an integer.)

13.17. is currently executing instructions after having read as far as line 5

of the ¬le expr.mf.

13.18. The pixel values of currentpicture become 1 if they were ±1, otherwise they

become 0.

13.19. (a) addto V1 also V2 ; cull V1 keeping (2, 2). (b) Same, but cull keeping

(1, 2). (c) Same, but cull keeping (1, 1).

13.20. Subtract one from the other, and cull the result dropping (0, 0); then test to

see if the total weight is zero.

13.21. (a) Same as ˜draw p™, but using q instead of the currently-picked-up pen.

(b) Same e¬ect as ˜draw p; draw p; draw p™ (but faster). (c) Same as ˜draw p

withweight w™, because undraw™s ˜withweight ’1™ is overridden. (d) Same as

˜un¬lldraw c; un¬lldraw c™, but using q instead of currentpen . (e) Same as ˜erase

¬lldraw c™, because the ˜withweight 2™ is overridden. [Since erase has culled all

weights to 0 or 1, there™s no need to “doubly erase.”] (f) Same e¬ect as ˜cullit; addto

currentpicture also currentpicture ™ (but faster).

13.22. vardef safe¬ll expr c = save region ;

picture region ; region =nullpicture;

interim turningcheck := 0;

addto region contour c; cull region dropping (0, 0);

addto currentpicture also region enddef .

13.23. cull currentpicture keeping (1, in¬nity );

picture v; v := currentpicture ;

cull currentpicture keeping (1, 1) withweight 3;

addto currentpicture also v ’ v shifted right

’ v shifted left ’ v shifted up ’ v shifted down ;

cull currentpicture keeping (1, 4).

Appendix A: Answers to All the Exercises 245

13.24. (We assume that currentpicture initially has some con¬guration in which all directiontime

pixel values are zero or one; one means “alive.”)

picture v; def c = currentpicture enddef ;

forever: v := c; showit;

addto c also c shifted left + c shifted right ;

addto c also c shifted up + c shifted down ;

addto c also c ’ v; cull c keeping (5, 7); endfor.

(It is wise not to waste too much computer time watching this program.)

14.1. beginchar ("b", 5pt #, 5pt #, 0);

¬ll ((0, 0) - - quartercircle - - cycle) scaled 10pt ; endchar.

1

14.2. A quartercircle corresponds to a circle whose diameter is 1; the radius is .

2

14.3. beginchar ("c", 5pt #, 5pt #, 0);

pickup pencircle scaled (.4pt + blacker );

draw quartercircle rotated 90 scaled 10pt shifted (5pt , 0); endchar.

14.4. beginchar ("d", 5pt # — sqrt 2, 5pt #, 0);

pickup pencircle scaled (.4pt + blacker );

draw ((0, 0) - - quartercircle - - cycle) rotated 45 scaled 10pt shifted (.5w, 0);

endchar.

14.5. beginchar ("e", 10pt #, 7.5pt #, 2.5pt #);

pickup pencircle scaled (.4pt + blacker );

for D = .2w, .6w, w: draw fullcircle scaled D shifted (.5w, .5[’d, h]);

endfor endchar.

The program for ˜ ™ is similar, but ˜fullcircle scaled D™ is replaced by

unitsquare shifted ’(.5, .5) rotated 45 scaled (D/ sqrt 2).

14.6. There are in¬‚ection points, because there are no bounding triangles for the

˜. . .™ operations in the superellipse macro of Appendix B, unless .5 ¤ s ¤ 1.

14.7. (0, 0) . . (1, 0) & (1, 0) . . (1, 1) & (1, 1) . . (0, 1) & (0, 1) . . (0, 0) & cycle.

Incidentally, if each ˜&™ in this path is changed to ˜. .™, we get a path that goes through

the same points; but it is a path of length 8 that comes to a complete stop at each

corner. In other words, the path remains motionless between times 1 ¤ t ¤ 2, 3 ¤ t ¤ 4,

etc. This length-8 path therefore behaves somewhat strangely with respect to the

˜directiontime™ operation. It™s better to use ˜&™ than to repeat points of a path.

14.8. Let δ1 = z1 ’ z0 , δ2 = z2 ’ z1 , δ3 = z0 ’ z2 ; l1 = |δ1 |, l2 = |δ2 |, l3 = |δ3 |;

ψ1 = arg(δ2 /δ1 ), ψ2 = arg(δ3 /δ2 ), ψ3 = arg(δ1 /δ3 ). The equations to be solved are (—)

and (——) for 1 ¤ k ¤ 3, where ±3 = ±0 and β4 = β1 . These six equations determine

θ1 , θ2 , θ3 and φ1 , φ2 , φ3 .

14.9. The path is of length 9, and it is equivalent to ˜(0, 1) - - (1, 1) - - (1, 2) - -

(0, 2) - - (0, 1){down } . . {right }(1, 0) - - (2, 0) - - (2, 1) - - (1, 1) - - (1, 0)™. Although

unitsquare is a cycle, the cycle is broken when it is used inside a larger path; the

resulting non-cyclic square path goes down when it ends and right when it begins.

246 Appendix A: Answers to All the Exercises

14.10. Yes; for example, ˜z0 . . z1 . . z2 - - z3 ™ would be equivalent to ˜z0 . . z1 . . Bernshte˜

±n

{curl 2}z2 {curl 2} . . {curl 2}z3 ™. But a path like z0 - - z1 - - z2 - - z3 would not be

a¬ected, because all directions would turn out to be the same as before. (The path

˜z0 {curl a} . . {curl b}z1 ™ is a straight line regardless of the values of a and b, because

equations (———) and (——— ) always have the solution θ0 = φ1 = 0 when n = 1.)

14.11. It treats this as ˜((0, 0) . . (3, 3) . . cycle){curl 1}™; i.e., the part up to and

including ˜cycle™ is treated as a subpath (cf. ˜p2™ in Chapter 8). The cycle is broken, after

which we have ˜(0, 0) . . controls (2, ’2) and (5, 1) . . (3, 3) . . controls (1, 5) and (’2, 2) . .

(0, 0){curl 1}™. Finally the ˜{curl 1}™ is dropped, because all control points are known.

(The syntax by itself isn™t really enough to answer this question, as you probably

realize. You also need to be told that the computation of directions and control points

is performed whenever uses the second or third alternative in the de¬nition

of path expression .)

14.12. True. The length of a path is the number of ˜zk . . controls uk and vk+1 . . zk+1 ™

segments that it contains, after all control points have been chosen.

14.13. True if 0 ¤ t ¤ 1, except perhaps for rounding errors; otherwise false. The

path z0 - - z1 expands into ˜z0 . . controls 1/3[z0 , z1 ] and 2/3[z0 , z1 ] . . z1 ™, and the

Bernshte˜ polynomial simpli¬es because t[w, w + δ, w + 2δ, w + 3δ] = w + 3tδ. In-

±n

cidentally, ˜point t of (z0 - - - z1 )™ is usually quite di¬erent from t[z0 , z1 ].

14.14. If p is a cycle, or if p is a path of length ≥ 4, the stated subpath has length 2.

Otherwise the length is max(0, length p ’ 2).

14.15. vardef posttension expr t of p =

save q; path q;

q = point t of p {direction t of p} . . {direction t + 1 of p} point t + 1 of p;

length(postcontrol 0 of q ’ point 0 of q)

/length(postcontrol t of p ’ point t of p) enddef ;

vardef pretension expr t of p =

save q; path q;

q = point t ’ 1 of p {direction t ’ 1 of p} . . {direction t of p} point t of p;

length(precontrol 1 of q ’ point 1 of q)

/length(precontrol t of p ’ point t of p) enddef ;

The stated posttension turns out to be 4.54019.

14.16. The ˜&™ had to be changed to ˜. .™, because point t of p might not be exactly

equal to point u of q.

14.17. Since p intersects itself in¬nitely often at times (t, t), the task may seem im-

possible; but ™s shu¬„ed-binary search procedure provides a way. Namely,

p intersectiontimes reverse p = (0.17227, 0.28339), from which we can deduce that

t = 0.17227 and 1 ’ u = 0.28339.

15.1. (x,-y).

15.2. (x, y) rotated 180, or (x, y) scaled ’1.

15.3. True if and only if xpart t = ypart t = 0. If the stated equation holds for

at least one pair (x, y), it holds for all (x, y). According to the syntax of Chapter 8,

Appendix A: Answers to All the Exercises 247

interprets ˜’(x, y) transformed t™ as (’(x, y)) transformed t. (Inciden- a¬ne transformations

homogeneous

tally, mathematicians call ™s transformers “a¬ne transformations,” and the

parentheses

special case in which the xpart and ypart are zero is called “homogeneous.”) makepath

¬llin

15.4. z1 + z2 . commutativity

capsule

15.5. beginchar(126, 25u#, hheight # + border #, 0); "Dangerous left bend";

currentpicture := dbend re¬‚ectedabout ((.5w, 0), (.5w, h)); endchar;

The same idea can be used to create right parentheses as perfect mirror images of left

parentheses, etc., if the parentheses aren™t slanted.

15.6. Change line 9 to

draw (z1 . . . p) rotatedaround((.5w, .5h), ’45)

withpen pencircle scaled 3/4pt yscaled 1/3 rotated ’15;

15.7. Replace line 10 by

pickup pencircle scaled 3/4pt yscaled 1/3 rotated ’60;

draw (z1 . . . p) transformed t;

16.1. If there are two points zk and zk+1 with maximum y coordinate, the value of

˜peno¬set (’in¬nity , epsilon ) of p™ will be zk and ˜peno¬set (’in¬nity , ’epsilon ) of p™

will be zk+1 ; ˜peno¬set left of p™ will be one or the other. If there™s only one top point,

all three of these formulas will produce it. (Actually also allows pens to

be made with three or more vertices in a straight line. If there are more than two top

vertices, you can use peno¬set to discover the ¬rst and the last, as above; furthermore,

if you really want to ¬nd them all, makepath will produce a path from which they

can be deduced in a straightforward manner.)

16.2. ˜pencircle scaled 1.06060™ is the diamond but ˜pencircle scaled 1.06061™

is the square. (This assumes that ¬llin = 0. If, for example, ¬llin = .1, the change

doesn™t occur until the diameter is 1.20204.) The next change is at diameter 1.5, which

gives a diamond twice the size of the ¬rst.

17.1. (a + 1) + (2a + 2) = 3a + 3 and (2a) + (2a + 1) = 4a + 1, respectively. The

¬nal value of x in the ¬rst case is 2a + 2, hence a = .5x ’ 1; expr will report the answer

as 1.5x (in terms of x™s new value), since it has not been told about ˜a™. In the second

case expr will, similarly, say 2x-1.

This example shows that ± + β is not necessarily equal to β + ±, when ± and β

involve group expressions. evaluates expressions strictly from left to right,

performing the statements within groups as they appear.