|
|
1.1 root 1: .so ../ADM/mac
2: .XX anim 451 "A System for Algorithm Animation"
3: .EQ
4: delim @@
5: .EN
6: .nr dP 1
7: .nr dV 1
8: .nr dT 8 \" tab stops this far apart in .P1/.P2
9: .nr NH .5v \" adds extra space before NH or SH heading
10: .nr ds .5i \" default indent for programs
11: .hy 14 \" set hyphenation: 2=not last lines; 4= no -xx; 8=no xx-
12: .\"
13: .de IN \" assumes called as .INCLUDE filename
14: .sy compile \\$2.t
15: .so \\$2.o
16: ..
17: .de ge \" assumes .ge called as .get
18: .sy trget \\n(.$ \\$2 '\\$3' '\\$4' '\\$5' >junk.\\n($$
19: .so junk.\\n($$
20: .sy rm junk.\\n($$
21: ..
22: .de ru \" assumes .ru called as .run
23: .sy \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 >junk1.\\n($$
24: .get junk1.\\n($$
25: .sy rm junk1.\\n($$
26: ..
27: .TL
28: A System for Algorithm Animation
29: .br
30: Tutorial and User Manual
31: .AU
32: Jon L. Bentley
33: Brian W. Kernighan
34: .AI
35: .MH
36: .AB
37: A program or an algorithm can be animated by a movie
38: that graphically represents its dynamic execution.
39: For instance, a memory allocator might be animated by lines that
40: appear when memory is allocated and disappear when it is freed;
41: a sort might be animated by a randomly scrambled
42: sequence of lines being permuted into order.
43: Such animations are useful for debugging programs, for developing
44: new programs, and for communicating information about how programs work.
45: This paper describes a basic system for algorithm animation:
46: the output is crude, but the system is easy to use;
47: novice users can animate a program in a couple of hours.
48: The system currently produces movies on Teletype 5620 terminals
49: and workstations that support the X window system, and also renders movies into
50: ``stills'' that can be included in
51: .I troff
52: documents.
53: This paper is a user manual and a tutorial introduction
54: to algorithm animation using the system.
55: .AE
56: .NH
57: Introduction
58: .PP
59: Dynamic displays are better than static displays for
60: giving insight into the behavior of dynamic systems.
61: The pictures in Figure 1, for instance, illustrate four
62: equal-mass bodies moving in the plane
63: under Newtonian attraction.
64: .KF
65: .INCLUDE stars
66: .sp
67: .ce
68: \f3Figure 1:\fP Bodies moving under Newtonian attraction
69: .KE
70: Time marches across the pictures left to right,
71: at roughly equal intervals.
72: Each column, called a
73: .I snapshot ,
74: depicts three
75: .I views
76: of the bodies.
77: The top view gives the current position as a dot; the tail formed
78: by the last few positions hints at the velocity and the acceleration.
79: The middle view renders the path of each body as a line.
80: The bottom view depicts the history of velocities by dots
81: recorded at equal time intervals:
82: low velocities give close dots and
83: high velocities leave the dots far apart.
84: .PP
85: The first snapshot shows the bodies starting slowly, far apart.
86: In the second snapshot they have recently experienced a
87: high-velocity encounter near the center.
88: In the third snapshot the bodies are again far apart,
89: moving slowly toward another encounter in the fourth snapshot.
90: In the fifth snapshot the large time-step of our simulation program
91: violates conservation of energy and sends the bodies racing away
92: from each other.
93: .PP
94: This paper describes the animation system that produced those pictures.
95: A sixty-line C simulation program was augmented with eight
96: .I printf
97: statements to generate a
98: .I script
99: file describing the paths of the four bodies in the three views.
100: That file was processed by a program named
101: .I stills
102: to produce the pictures above, using
103: .I pic
104: and
105: .I troff ;
106: we were able to control what frames were displayed, in what size and form.
107: A program named
108: .I movie
109: displays the same data on a Teletype 5620 terminal or an X workstation;
110: the viewer can control the speed of display,
111: proceed forward or backward through time,
112: and change the screen layout to emphasize certain views.
113: Those components can be depicted as:
114: .PS
115: boxht = .25; boxwid = .6
116: ellipseht = .25; ellipsewid = .6
117: lineht = .1; linewid = .4
118: down
119: box "generator"
120: line down
121: A: ellipse "script"
122: line from A.se right down
123: box "stills"
124: line down
125: box invis "pic | troff | ..."
126: line from A.sw left down
127: box "movie"
128: line down
129: box invis "5620, X, ..."
130: .PE
131: .PP
132: Several systems have been developed for algorithm animation
133: |reference(sedgewick brown ieee).
134: Most of those systems produce animations of very high quality;
135: unfortunately, they are expensive in both programmer time and CPU time.
136: Our system is at the opposite end of the spectrum:
137: its output is primitive, but the system is easy to use;
138: a new user can animate a simple program
139: in an hour or two by adding a few lines of code.
140: Although our system was designed primarily with program animation
141: in mind, the gravitational example shows that it can be useful
142: in other domains as well.
143: .PP
144: Section 2 introduces the system by animating a sorting algorithm.
145: Sections 3 through 5 describe the three primary components of
146: the system:
147: script
148: files,
149: .I movie ,
150: and
151: .I stills .
152: Section 6 describes the animation of several larger programs,
153: and Section 7 discusses a few everyday matters about using the system.
154: .NH
155: A Simple Example \(em Sorting
156: .PP
157: Insertion sort is the method most card players use.
158: As each card is dealt, it is inserted into
159: its proper place among the existing cards.
160: To sort the array @X[1..N]@, insertion sort maintains the
161: sorted subset in @X[1..I]@ and increases @I@ from 2 to @N@.
162: The subarray @X[1..1]@ is sorted by definition.
163: The first phase of the algorithm sifts @X[2]@ down
164: so that @X[1..2]@ is sorted, the second phase sifts
165: @X[3]@ down so that @X[1..3]@ is sorted, and so on.
166: .PP
167: Here is an implementation of insertion sort in
168: .I awk |reference(awk book):
169: .P1
170: .get is.awk
171: .P2
172: The first
173: .CW for
174: statement sprinkles
175: .CW x[1..n]
176: with random integers in the range @1..25@, and the second and third
177: .CW for
178: statements perform the insertion sort.
179: The function
180: .CW swap
181: exchanges array elements;
182: .CW show
183: prints the current state of the array.
184: .PP
185: If we run this program with
186: .CW n
187: set to 7, we get this static display
188: of sorting a 7-element array of random integers:
189: .P1
190: .run sh is.awk 7
191: .P2
192: .PP
193: The animation system provides an alternative:
194: by adding a few more
195: .CW print
196: statements to the program, we can produce input for the animation system,
197: thus providing a dynamic display
198: of the sorting process.
199: Furthermore, we can use graphics as well as text,
200: to give a more visual presentation of the algorithm.
201: .PP
202: For this example, we decided to present two
203: views.
204: The top view simply shows the numbers in the array as they are sorted;
205: it is essentially the same as the textual output above,
206: except that we have added a vertical bar:
207: elements to the left of the bar are in order.
208: The bottom view is graphical: the value of each element is represented
209: by the length of the corresponding vertical line.
210: .PP
211: These six snapshots
212: show the state after each phase of the sorting algorithm:
213: .sy make.sorts
214: .INCLUDE is3
215: .PP
216: Although the two views represent the same information,
217: they are useful for different tasks.
218: The textual nature of the top view is easier for novices to follow,
219: and the complete information is handy for debugging small examples.
220: The more visual bottom view is better for displaying large sorts.
221: .sp 1
222: .LP
223: .I "The Program."
224: .PP
225: Here is the complete
226: .I awk
227: program
228: .CW is.gen
229: that generated the animation depicted above.
230: .P1
231: .get is.gen
232: .P2
233: It is very similar to the first version,
234: but we have added the functions
235: .CW less
236: to make comparisons and
237: .CW draw
238: to display elements,
239: as well as several
240: .CW print
241: statements.
242: In addition to performing their sorting functions,
243: .CW less
244: and
245: .CW swap
246: record their actions by printing output
247: into a script file that will serve as input to
248: .I movie
249: and
250: .I stills .
251: This animation uses four commands:
252: .CW line ,
253: .CW text ,
254: .CW view
255: and
256: .CW click .
257: .PP
258: A line from @( x sub 1 , y sub 1 )@ to @( x sub 2 , y sub 2 )@ is
259: drawn by a command of the form
260: .P1
261: @optional_label:@ line @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@
262: .P2
263: (Throughout this paper, literals are shown in
264: .CW typewriter
265: font and categories are in @italics@.)
266: The coordinates of the line can lie in any range;
267: later programs will scale them appropriately.
268: The label on a line is optional.
269: When a labeled object is drawn
270: the object that previously had that label is erased.
271: Thus for all lines that have the same label,
272: the act of drawing one line erases its predecessor.
273: (There is also an explicit
274: .CW erase
275: command.)
276: .PP
277: Text is produced at @( x , y )@ by a command of the form
278: .P1
279: @optional_label:@ text @x@ @y@ @anything@ @at@ @all@
280: .P2
281: As with lines, labels are permitted;
282: re-use of a label erases whatever object previously had that label.
283: For example, the vertical bar is always printed with the label
284: .CW bar ,
285: so each bar erases the previous one.
286: .PP
287: The
288: .CW view
289: command is used to place output in a particular view.
290: There are two views here,
291: .CW text
292: and
293: .CW geom :
294: .P1
295: view text
296: view geom
297: .P2
298: The
299: .CW draw
300: function draws text in the
301: .CW text
302: view
303: and lines in the
304: .CW geom
305: view, relying on implicit erasure to remove the previous object
306: before creating a new one.
307: Different views are independent, so a label like
308: .CW a1
309: can be used in several views without interference.
310: .PP
311: Interesting events are marked by the
312: .CW click
313: command:
314: .P1
315: click swap
316: click comp
317: click phase
318: .P2
319: .I Stills
320: and
321: .I movie
322: can refer to each click with this mechanism,
323: as we will see in more detail shortly.
324: .PP
325: Labels, view names and click names are arbitrary
326: and unrelated to one another.
327: .sp 1
328: .LP
329: .I "The Script File."
330: .PP
331: Executing the command
332: .P1
333: is.gen 3 >is1.s
334: .P2
335: produces the script file
336: .CW is1.s
337: containing a sort of three elements.
338: The basename
339: .CW is1
340: is for ``insertion sort 1''; the suffix
341: .CW .s
342: identifies it as a script file and is required by the animation system.
343: Here is
344: .CW is1.s ,
345: printed in two columns to save space:
346: .P1
347: .ps 8
348: .vs 8
349: .ta 3i
350: .run 2col is1.s
351: .P2
352: .sp
353: .PP
354: Here is a picture of all clicks in the script file
355: .CW is1.s ,
356: produced by
357: .I stills .
358: .INCLUDE is1
359: As before, time goes from left to right.
360: Both views of the current state are depicted in a snapshot at each
361: .CW click ;
362: the label below each frame tells the name and number of the click.
363: This detailed picture illustrates the animation system;
364: here is a sparser picture that illustrates insertion sort
365: on a 14-element array:
366: .INCLUDE is2
367: .sp 1
368: .LP
369: .I "Making Stills."
370: .PP
371: The last picture was included in this document by this
372: .I stills
373: description:
374: .P1
375: .get is2.t
376: .P2
377: The description is delimited by the lines
378: .CW "\&.begin stills"
379: and
380: .CW \&.end
381: (which correspond, for instance, to
382: .CW \&.EQ
383: and
384: .CW \&.EN
385: in
386: .CW eqn
387: or
388: .CW \&.TS
389: and
390: .CW \&.TE
391: in
392: .CW tbl ).
393: Text following the sharp character
394: .CW #
395: is a comment to be ignored.
396: The
397: .CW view
398: statements specify the empty string as the title for both
399: views of the data.
400: The
401: .CW print
402: statement displays snapshots at the requested
403: .CW click s
404: of
405: .CW phase .
406: .PP
407: The last four statements are parameter assignments of the form
408: .P1
409: @parameter_name@ @value@
410: .P2
411: Assignment to the
412: .CW file
413: parameter names the script file to be displayed.
414: The next two assignments set the height and width of frames,
415: and the final statement causes
416: .CW medium
417: text (the default text size) to be set
418: five points smaller than the current
419: .I troff
420: point size.
421: .sp 1
422: .LP
423: .I "Viewing A Movie."
424: .PP
425: To watch a movie on the 5620,
426: make a window of suitable size and shape
427: and in it type the command
428: .P1
429: is.gen 20 | movie
430: .P2
431: If you want to access the script later, type instead
432: .P1
433: is.gen 20 >is.s
434: movie is.s
435: .P2
436: After a pause to run
437: .CW is.gen
438: (about 15 seconds on a VAX\(tm-750 in this case), the 5620 down-loading procedure
439: will begin;
440: after that (another 30 seconds), the data for the movie itself will
441: begin to appear.
442: When this is finished (also about 30 seconds),
443: a message about the number of bytes
444: sent (about 9500) appears in the upper left corner.
445: .PP
446: At this point, the mouse buttons can be used to
447: redisplay the movie.
448: Button 3 is the main control.
449: It has 9 menu items:
450: .P1
451: again
452: faster 1
453: slower 1
454: 1 step
455: backward
456: fatter 1
457: thinner 1
458: or mode
459: new file
460: Quit?
461: .P2
462: To play the movie again,
463: select
464: .CW again .
465: (This movie takes about 6 seconds at full speed.)
466: You can stop it at any point by pushing any button;
467: a further push of button 1 continues it.
468: To slow the display, select
469: .CW slower ;
470: each selection halves the speed by increasing
471: a wait interval by a factor of two.
472: After three selections the menu reads
473: .P1
474: again
475: faster 8
476: slower 8
477: \&...
478: .P2
479: Try selecting
480: .CW again
481: to see the sort once at this speed, then select
482: .CW faster
483: three times to get back to full speed.
484: .PP
485: The items labeled
486: .CW fatter
487: and
488: .CW thinner
489: control the thickness of lines in an analogous manner.
490: Selecting
491: .CW fatter
492: several times results in obese lines;
493: you may return things to normal with
494: .CW thinner .
495: .PP
496: Three menu items control binary mode settings:
497: .CW 1
498: .CW step
499: or
500: .CW run ;
501: .CW backward
502: or
503: .CW forward ;
504: and
505: .CW or
506: .CW mode
507: or
508: .CW xor
509: .CW mode .
510: For each, the label indicates the next state,
511: not the current state.
512: .PP
513: Normally the movie is played from beginning to end without pause.
514: The menu item labeled
515: .CW 1
516: .CW step
517: puts it into a mode where it displays only one ``step''
518: each time button 1 is pushed.
519: This allows you to inspect the sort a frame at a time.
520: This item changes to
521: .CW run
522: when
523: .CW 1
524: .CW step
525: has been selected
526: so you can revert to continuous action.
527: .PP
528: The
529: .CW backward
530: item causes the steps to be taken in reverse order (time runs backwards);
531: the menu item changes to
532: .CW forward
533: when selected.
534: After the sort ends, select
535: .CW backward
536: and
537: .CW again
538: and watch the array scramble itself before your very eyes.
539: Judicious use of
540: .CW 1
541: .CW step
542: and
543: .CW backward
544: and
545: .CW forward
546: make it easy to examine a few snapshots in detail.
547: .PP
548: Normally items are displayed in ``exclusive OR'' mode,
549: which means that a bit drawn over a previous one erases it.
550: If you are drawing numerous objects in a crowded area,
551: this can lead to unintended erasures.
552: The
553: .CW or
554: .CW mode
555: item switches to ``inclusive OR'' for drawing objects,
556: and erases objects by clearing.
557: Some movies are far better in one mode than the other.
558: .PP
559: The
560: .CW new
561: .CW file
562: item allows one to view a new movie without having to reload the
563: .I movie
564: program into the 5620.
565: We'll see how it works in Section 4.
566: .PP
567: The
568: .CW Quit?
569: menu item is the way to exit.
570: If selected, it displays a skull and crossbones
571: to warn that its effect is irreversible.
572: Pushing button 3 again exits;
573: a different button avoids quitting.
574: .PP
575: Button 2 contains menu items to control the size and shape
576: of the views on the screen and to control the meaning of a
577: ``step'' in 1-step mode.
578: For this sorting movie, button 2 looks like:
579: .P1
580: view text
581: view geom
582: click comp
583: click swap
584: click phase
585: .P2
586: When a view is selected, you can sweep a rectangle
587: in which that view is to be displayed;
588: the use is exactly like the
589: .CW New
590: menu item in
591: .I mux .
592: You can arrange the views any way you like;
593: try deleting the textual view by sweeping its rectangle out of the window.
594: .PP
595: When a
596: .CW click
597: is selected, 1-stepping proceeds to the next
598: occurrence of that click.
599: So, for example, to see swaps one at a time,
600: select
601: .CW click
602: .CW swap
603: on button 2 then select
604: .CW 1
605: .CW step
606: on button 3.
607: Each hit of button 1 will pause at the next
608: .CW click
609: .CW swap
610: statement in the script file, in either
611: .CW forward
612: and
613: .CW backward
614: mode.
615: .PP
616: Multiple clicks may be selected.
617: Selecting both
618: .CW click
619: .CW comp
620: and
621: .CW click
622: .CW swap
623: will cause a pause after every comparison and every swap.
624: Selected clicks are marked with an asterisk in the menu;
625: selecting a click that already has an asterisk
626: removes the asterisk and turns off the click.
627: .PP
628: In
629: .CW run
630: mode, the movie runs at full speed until it encounters a selected click,
631: then pauses for a time proportional to the selected speed.
632: Selecting no clicks is equivalent to having selected an implicit
633: click that occurs after each geometric object
634: (text, line, circle, rectangle)
635: is drawn or erased,
636: so animations run faster when some clicks are turned on (with
637: .CW click
638: .CW phase
639: selected, for instance, the sorting movie runs nearly twice as fast).
640: .sp 1
641: .LP
642: .I "Summary."
643: .PP
644: This exercise illustrates the capabilities
645: and limitations of our animation system.
646: The output of
647: .I movie
648: is a crude but useful animation.
649: The output of
650: .I stills
651: is handy for more detailed study and for presentation in documents
652: (we would like to include a movie in this document, for instance,
653: but paper is easier to distribute than videotape).
654: A sophisticated animation system might require 500 lines of
655: code to produce beautiful animations of insertion sort.
656: Our output is unpolished by comparison, but it is adequate
657: for many purposes and requires just a few dozen lines.
658: .PP
659: If our system is so crude, why bother using it?
660: Why not animate an algorithm simply by drawing geometric objects
661: on the output device you happen to be using?
662: Some of the answer lies in extra services like these:
663: .IP
664: .I "Device Independence."
665: A script file can be rendered as a movie on a 5620 or an X11 workstation;
666: the system is designed to make it easy to port to additional
667: output devices.
668: The same script file can be incorporated into a document by
669: .I stills .
670: .IP
671: .I "Names."
672: Labels allow geometric objects to be erased;
673: implicit erasure by re-using a label avoids
674: much of the tedium of bookkeeping.
675: Click names mark key events;
676: they can be used to group related events.
677: .IP
678: .I "Independent Views."
679: Different simultaneous views of a process
680: are crucial for animating algorithms.
681: In our system, a single statement moves from one view to another.
682: Within a view, the user need not be
683: concerned about the range of coordinates;
684: the system scales automatically.
685: Labels in different views are independent.
686: .IP
687: .I "Viewer Control."
688: Both
689: .I movie
690: and
691: .I stills
692: allow the viewer to select which views will be displayed
693: and which clicks will be recognized.
694: Additionally,
695: .I movie
696: allows the viewer to go forward or backward, in single
697: steps or running at a selected speed.
698: .IP
699: .I "An Interface To The World."
700: Although writing to files takes more computer time than using the
701: geometric primitives provided by a specific output device,
702: we will soon see how those files allow complicated tasks
703: to be easily composed out of simple software tools.
704: .LP
705: Our system does not support interactive animations, however:
706: once the script has been generated,
707: there's no way to change it
708: except to generate it again.
709: .NH
710: The Script Language
711: .PP
712: This section is a more complete description of the
713: script language in which animations are described.
714: A script file is processed by the heretofore unmentioned program
715: .I develop ;
716: errors in script files are reported by that program.
717: The output of
718: .I develop
719: feeds
720: .I stills
721: and
722: .I movie :
723: .PS
724: boxht = .25; boxwid = .6
725: ellipseht = .25; ellipsewid = .6
726: lineht = .1; linewid = .4
727: down
728: box "generator"
729: line down
730: ellipse "fname.s"
731: line down
732: box "develop"
733: line down
734: A: ellipse "fname.i"
735: B: box "stills" with .w at A.e + (.2, -.4)
736: line down
737: box invis "pic | troff | ..."
738: C: box "movie" with .e at A.w - (.2, .4)
739: line down
740: box invis "5620, X, ..."
741: line from A.se to B.nw
742: line from A.sw to C.ne
743: up
744: line up from B.n
745: ellipse "docfile"
746: .PE
747: The command
748: .CW develop
749: .CW fname.s
750: produces the
751: .I intermediate
752: file
753: .CW fname.i
754: from the script file
755: .CW fname.s ,
756: unless
757: .CW fname.i
758: already exists and is newer than
759: the corresponding script file.
760: Fortunately, most users need not be concerned with intermediate files and the
761: .I develop
762: program; both
763: .I movie
764: and
765: .I stills
766: call
767: .I develop
768: implicitly.
769: Appendix I defines the format of an intermediate file.
770: .PP
771: The script language provides
772: commands to draw geometric objects
773: and commands that control the pictures.
774: A line whose first non-blank character is
775: .CW #
776: is a comment;
777: comments may not appear on the line after other commands.
778: Blank lines are ignored.
779: .sp 1
780: .LP
781: .I "Geometric Commands" :
782: .CW text ,
783: .CW line ,
784: .CW box ,
785: .CW circle .
786: .PP
787: Geometric commands describe text, lines, rectangles, or circles.
788: They share the common form
789: .P1
790: @optional_label:@ @command@ @options@ @x@ @y@ @additional@ @parts@
791: .P2
792: If a label is present, it names the object and will implicitly
793: erase any existing object with the same name in the same view.
794: The options are a (possibly null) list of names,
795: terminated by the next numeric field.
796: .PP
797: Text is placed at a position by the command
798: .P1
799: @optional_label:@ text @options@ @x@ @y@ @string@
800: .P2
801: The available options are
802: .P1
803: [center] ljust rjust above below
804: small [medium] big bigbig
805: .P2
806: At most one option may be selected from each line;
807: if none is selected, the option in brackets is used.
808: The first line describes text position, and
809: the second line describes text size.
810: The text string may be quoted.
811: If there is no leading quote, then the string starts at the first
812: non-blank character and continues until the end of the line.
813: If there is a leading quote, subsequent leading white space is kept
814: and any trailing quote at the end of the line is removed;
815: intermediate quotes are kept.
816: Some strings, including
817: (but not necessarily limited to)
818: .CW bullet ,
819: .CW dot ,
820: .CW circle ,
821: and
822: .CW times ,
823: are recognized by later processors.
824: .PP
825: A line is drawn by
826: .P1
827: @optional_label:@ line @options@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@
828: .P2
829: The available options are
830: .P1
831: [-] -> <- <->
832: [solid] fat fatfat dotted dashed
833: .P2
834: The first line of options describe whether the line should
835: be drawn with arrowheads; the default is without arrowheads.
836: The option
837: .CW <-
838: puts an arrowhead at the @( x sub 1 , y sub 1 )@ end of the line,
839: .CW ->
840: puts an arrowhead at the other end,
841: and
842: .CW <->
843: puts them at both ends.
844: The second line of options describes the body of the line.
845: .PP
846: A rectangle is drawn by
847: .P1
848: @optional_label:@ box @options@ @xmin@ @ymin@ @xmax@ @ymax@
849: .P2
850: The only options are
851: .P1
852: [nofill] fill
853: .P2
854: Under the default
855: .CW nofill
856: only the border of the box is drawn;
857: a
858: .CW fill ed
859: box has a solid interior as well.
860: .PP
861: A circle is drawn by
862: .P1
863: @optional_label:@ circle @options@ @x@ @y@ @radius@
864: .P2
865: The radius is measured in the @x@ dimension.
866: Circles will look right only if @x@ and @y@ are in about the same range.
867: As with rectangles, the options are
868: .P1
869: [nofill] fill
870: .P2
871: .sp 1
872: .LP
873: .I "Control Commands" :
874: .CW view ,
875: .CW click ,
876: .CW erase ,
877: .CW clear .
878: .PP
879: The current view is set by the statement
880: .P1
881: view @name@
882: .P2
883: If there are no view statements in the script file,
884: .I develop
885: generates a single implicit view named
886: .CW def.view .
887: If geometric objects appear before the first view statement,
888: they go in that view and a warning message is generated.
889: .PP
890: A click is named by
891: .P1
892: click @optional_name@
893: .P2
894: If no name is present, then the name
895: .CW def.click
896: is implicitly supplied.
897: .PP
898: A labeled geometric object can be explicitly erased by the command
899: .P1
900: erase @label@
901: .P2
902: .I develop
903: prints a warning
904: if the object was never defined or has already been erased.
905: The various views have distinct name spaces;
906: the same label may be applied to two unrelated objects in two different views.
907: All objects in the current view can be erased by the statement
908: .P1
909: clear
910: .P2
911: .PP
912: None of these commands may have labels.
913: .sp 1
914: .LP
915: .I "Summary."
916: .PP
917: The script language contains the following commands;
918: options are indented on a subsequent line, with defaults in brackets:
919: .P1
920: # comment
921: @optional_label:@ line @options@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@
922: [-] -> <- <->
923: [solid] fat fatfat dotted dashed
924: @optional_label:@ text @options@ @x@ @y@ @string@
925: [center] ljust rjust above below
926: small [medium] big bigbig
927: @optional_label:@ box @options@ @xmin@ @ymin@ @xmax@ @ymax@
928: [nofill] fill
929: @optional_label:@ circle @options@ @x@ @y@ @radius@
930: [nofill] fill
931: view @name@
932: click @optional_name@
933: erase @label@
934: clear
935: .P2
936: .PP
937: The shell command
938: .CW develop
939: .CW fname.s
940: makes the intermediate file
941: .CW fname.i
942: from the script file
943: .CW fname.s ,
944: if
945: .CW fname.i
946: is out of date.
947: The purpose of the intermediate file is to trade
948: increased space (for storing the intermediate file) for
949: reduced run time (a script file is developed just once, not
950: each time it is used).
951: The
952: .I movie
953: and
954: .I stills
955: shell scripts could be rewritten to pipe their inputs through
956: .I fdevelop ,
957: a filter form of
958: .I develop .
959: The
960: .I fdevelop
961: program can handle script files with at most 20,000 lines;
962: the argument
963: .CW -l\f2n\fP
964: changes the upper bound to
965: .I n
966: instead.
967: It can similarly handle at most 10,000 pieces of geometry
968: active at any time;
969: the argument
970: .CW -s\f2n\fP
971: (for ``slots'') changes that upper bound.
972: Error messages tell when these bounds need to be increased.
973: After any
974: .CW -l
975: and
976: .CW -s
977: arguments,
978: .I fdevelop
979: can have an optional file name.
980: If there is a name, that is the input file; otherwise,
981: the standard input is used.
982: The output is written on
983: the standard output.
984: .NH
985: The Movie Program
986: .PP
987: Movie production, as with most 5620 programs,
988: uses a host process and a terminal process.
989: The host sends the intermediate file produced by
990: .I develop
991: in a compact form to the terminal,
992: which stores it in a form suited
993: for forward or backward display.
994: As the file is shipped, the line number in
995: the intermediate file is displayed in the
996: upper-left corner of the window every 100 lines.
997: Afterwards, the total number of bytes
998: stored is displayed in that location.
999: The terminal process allocates 80,000 bytes
1000: (typically 5-10,000 objects)
1001: for the picture;
1002: the argument
1003: .CW -m\f2n\fP
1004: sets the allocation to
1005: .I n
1006: instead.
1007: .PP
1008: The button 3 menu was sketched in Section 2.
1009: In general, drawing can be interrupted at any point by
1010: pushing any button, then resumed by pushing button 1.
1011: .PP
1012: Four menu items control two variables:
1013: .P1
1014: faster [speed]
1015: slower [speed]
1016: .P2
1017: decrease (halve) and increase (double) the pause at selected clicks, and
1018: .P1
1019: thinner [line width]
1020: fatter [line width]
1021: .P2
1022: alter the width of lines.
1023: (If the line thickness is @n@, then
1024: .CW solid
1025: lines are @2n - 1@ bits wide;
1026: .CW fat
1027: and
1028: .CW fatfat
1029: lines are larger.)
1030: Three menu items control binary attributes:
1031: .P1
1032: backward forward
1033: or mode xor mode
1034: 1 step run
1035: .P2
1036: The mode displayed on the menu is the next state, not the current one.
1037: If the program is currently in
1038: .CW or
1039: .CW mode ,
1040: for instance, then
1041: .CW xor
1042: .CW mode
1043: is displayed.
1044: .PP
1045: The
1046: .CW new
1047: .CW file
1048: item allows one to view a new movie without downloading the
1049: .I movie
1050: program again.
1051: After selecting that item,
1052: text in the upper left of the window asks for the name of the intermediate
1053: file to be processed.
1054: The
1055: .I movie
1056: program does not call
1057: .I develop
1058: to make the intermediate
1059: .CW .i ) (
1060: file from the script
1061: .CW .s ) (
1062: file;
1063: that is the responsibility of the user,
1064: typically in a separate window.
1065: .PP
1066: Button 2 lists views and clicks.
1067: Selecting a view results in an icon for sweeping a rectangle,
1068: as in
1069: .I mux .
1070: Views may be positioned anywhere;
1071: portions positioned outside the window will not be shown.
1072: Initially, views have a 5 percent margin at each edge;
1073: this margin is zero for views that have been reshaped.
1074: If the window itself is reshaped, all views revert to
1075: the default position and margin.
1076: .PP
1077: Normally, in 1-step mode, the display pauses after each
1078: primitive object (line, text, etc.) has been drawn or erased.
1079: If any clicks are defined and turned on by button 2, however,
1080: then the display pauses only at those points.
1081: Any number of clicks may be turned on.
1082: Clicks that are turned on are marked with an asterisk;
1083: they may be turned off by selecting them again.
1084: .PP
1085: As it is for the 5620, so it is for X workstations,
1086: although the exigencies of the X window system
1087: have forced us to curtail some features.
1088: To keep the code relatively portable,
1089: there are again two processes, so
1090: the window in which one starts the animation clones another
1091: window of uncontrolled size, shape and position
1092: where the animation itself occurs.
1093: .PP
1094: The current terminal programs support
1095: many, but not all, text size and line mode options.
1096: .PP
1097: If
1098: .I movie
1099: has a single argument, it must be either a
1100: .CW .s
1101: or
1102: .CW .i
1103: file;
1104: .I movie
1105: .I develop s
1106: a
1107: .CW .s
1108: file.
1109: If it has no arguments, then it will pipe
1110: the standard input
1111: through
1112: .I fdevelop ;
1113: no intermediate file is created.
1114: For more exotic situations, use
1115: .I fmovie :
1116: with no arguments, it projects the intermediate file
1117: from the standard input;
1118: with a single argument, it projects that intermediate file.
1119: .NH
1120: The Stills Language
1121: .PP
1122: The
1123: .I stills
1124: program is a typical
1125: .I troff
1126: preprocessor.
1127: Portions of its input bracketed by
1128: .CW .begin
1129: .CW stills
1130: and
1131: .CW .end
1132: are translated into
1133: .I pic
1134: commands, and the rest of the input is passed through untouched.
1135: A paper containing
1136: .I stills
1137: input is typically compiled by a command like
1138: .P1
1139: stills paper | pic | troff >paper.out
1140: .P2
1141: .PP
1142: There are three classes of statements in a
1143: .I stills
1144: description:
1145: .CW print ,
1146: .CW view ,
1147: and parameter assignments.
1148: Only two statements are mandatory in a particular description:
1149: an assignment to the
1150: .CW file
1151: parameter and a
1152: .CW print
1153: statement.
1154: Text following the sharp symbol
1155: .CW #
1156: is discarded as a comment; blank lines are ignored.
1157: .PP
1158: There may be any number of
1159: .CW print
1160: statements of any combination of the following forms:
1161: .P1
1162: print all
1163: print final
1164: print @clickname@ all
1165: print @clickname@ @number@ @number@ @number@ ...
1166: .P2
1167: The first statement causes a snapshot to be drawn at each
1168: .CW click
1169: statement in the script file; the second draws one at the end of the file.
1170: The third form prints all
1171: .CW click s
1172: of the designated name, and the fourth prints only the clicks enumerated
1173: in the list of numbers.
1174: .PP
1175: View statements select which views are to be printed in snapshots
1176: and assign titles to views.
1177: .P1
1178: view @name@ @optional@ @title@
1179: .P2
1180: The views appear in the order they are named,
1181: either top-to-bottom if time goes
1182: .CW across
1183: the page or left-to-right if time goes
1184: .CW down
1185: the page.
1186: If there are no
1187: .CW view
1188: statements, each snapshot depicts all views in the script.
1189: If the title is enclosed in quote marks, they are stripped and
1190: leading space is kept.
1191: If no title is given for a particular view, the view name
1192: itself is used as a title;
1193: thus an empty title is needed to turn off printing.
1194: .PP
1195: Parameters can be set by assignment statements of the form
1196: .P1
1197: @parameter_name@ @value@
1198: .P2
1199: All parameters are reset to their default values at each
1200: .CW .begin
1201: .I stills
1202: statement.
1203: Numeric values may be of the form
1204: .CW n ,
1205: .CW +n ,
1206: .CW -n ,
1207: or absent (zero default).
1208: .IP
1209: .I Filename
1210: parameter:
1211: .CW file .
1212: The script file is named by assigning to the
1213: .CW file
1214: parameter with a statement of the form
1215: .CW file
1216: .CW basename.s .
1217: The
1218: .I stills
1219: program
1220: .I develop s
1221: that script file and then reads
1222: .CW basename.i .
1223: .IP
1224: .I "Text sizes" :
1225: .CW "small medium big bigbig" .
1226: The assignment
1227: .CW small
1228: .CW -2
1229: causes text with the
1230: .CW small
1231: option to be printed two point sizes smaller than the current
1232: .I troff
1233: point size.
1234: Assigning
1235: .CW "+5"
1236: or
1237: .CW "5"
1238: to
1239: .CW "bigbig"
1240: increases the point size by 5 for
1241: .CW bigbig
1242: text.
1243: All changes are relative; there is no way to set
1244: absolute point size.
1245: .IP
1246: .I "Line widths" :
1247: .CW "solid fat fatfat" .
1248: Relative size changes for line widths, exactly as for text sizes.
1249: .IP
1250: .I "Direction" :
1251: .CW "across down" .
1252: By default, snapshots proceed across the page in time.
1253: The assignment
1254: .CW down
1255: .CW 5
1256: causes time to proceed down the page for 5 snapshots before
1257: starting a new column;
1258: .CW down
1259: .CW 0
1260: or
1261: .CW "down"
1262: yields as many snapshots as will fit on an 8-inch page.
1263: The assignment
1264: .CW across
1265: .CW 7
1266: gives 7 snapshots in a row before starting a new row;
1267: .CW across
1268: .CW 0
1269: or
1270: .CW across
1271: adapts to a 6-inch width.
1272: .IP
1273: .I "Frame parameters" :
1274: .CW "frameht framewid margin" .
1275: The height and width of frames are given in inches; defaults are 1.5.
1276: The margin of a frame is the white space surrounding the data;
1277: the default is 0.05, or a five percent border.
1278: .IP
1279: .I "Optional parts" :
1280: .CW "frames times" .
1281: Frames are the solid borders around pictures;
1282: times are the click name and number that triggered a snapshot.
1283: Both have the default value
1284: .CW vis
1285: and are shown; they may be suppressed by assigning them the value
1286: .CW invis .
1287: .PP
1288: In summary,
1289: .I stills
1290: input consists of these commands:
1291: .P1
1292: print all
1293: print final
1294: print @clickname@ all
1295: print @clickname@ @number@ @number@ @number@ ...
1296: view @name@ @optional@ @title@
1297: @parameter_name@ @value@
1298: .P2
1299: .LP
1300: At least one
1301: .CW print
1302: statement and a
1303: .CW file
1304: assignment are mandatory;
1305: other statements are optional.
1306: The parameter names in the right column may appear on the left side of a
1307: name/value assignment:
1308: .P1
1309: .ta 1.1i
1310: \f2Filename\fP file
1311: \f2Text sizes\fP small medium big bigbig
1312: \f2Line widths\fP solid fat fatfat
1313: \f2Direction\fP across down
1314: \f2Frame parameters\fP frameht framewid margin
1315: \f2Optional parts\fP frames times
1316: .P2
1317: .........
1318: .NH
1319: Larger Animations
1320: .PP
1321: The examples in this section illustrate algorithms on several
1322: classes of data structures, including arrays, trees and graphs.
1323: The graphical style is simple; this is easy for the animator and
1324: effective for the viewer.
1325: The programs in this section are not presented as paradigms of
1326: good programming style; rather, they show how succinct programs
1327: can yield useful animations.
1328: .PP
1329: In the paper cited earlier, Brown and Sedgewick employ
1330: several conceptual levels in animating an algorithm.
1331: .IP
1332: .I Execution.
1333: At one extreme is the program to be animated,
1334: executing on the data of interest.
1335: .IP
1336: .I "History of ``Interesting Events.''
1337: What events in a computation should be depicted in the animation?
1338: The simple animation of insertion sort in Section 2 used augmented
1339: .CW less
1340: and
1341: .CW swap
1342: routines to capture two primitives of most sorting programs:
1343: comparisons and data movements.
1344: It also explicitly recorded information associated with the
1345: interesting event of finishing a phase.
1346: .IP
1347: .I "Geometric interpretation of events.
1348: One must next decide how to represent
1349: the interesting events pictorially.
1350: An array of integers, for instance, might be represented by
1351: a sequence of numbers, a scatterplot of bullets, or a sequence
1352: of vertical bars.
1353: .IP
1354: .I "Rendering on a device.
1355: In our system, this is the job of
1356: .I movie
1357: and
1358: .I stills .
1359: .LP
1360: The sample program
1361: .CW is.gen
1362: identified interesting events and gave them
1363: a geometric interpretation in separate procedures
1364: within a single program.
1365: Alternatively, it may be more convenient
1366: to implement the various tasks as a pipeline of two programs:
1367: a generator program writes interesting events that
1368: are given a geometric interpretation by a program that writes
1369: a script file.
1370: .PP
1371: One usually prints a
1372: .CW click
1373: statement immediately after the event it marks.
1374: Sometimes, though, one draws additional objects to
1375: highlight the event, which are erased immediately after the
1376: .CW click .
1377: In that case, one uses a sequence like
1378: .P1
1379: @draw@ @event@ @E@
1380: @highlight@ @E@
1381: click E
1382: @remove@ @highlights@
1383: .P2
1384: .sp 1
1385: .LP
1386: .I "Sorting, Again."
1387: .PP
1388: We will return to the subject of
1389: sorting with a more interesting animation:
1390: a race of insertion sort versus quicksort.
1391: We will use the same insertion sort we saw earlier,
1392: and a quicksort described in Section 10.2 of |reference(programming pearls).
1393: The two sorting routines and their supporting functions
1394: are contained in this
1395: .I awk
1396: program:
1397: .P1
1398: .get race.gen
1399: .P2
1400: Quicksort is called as
1401: .CW "qsort(l,u)"
1402: to sort the subarray
1403: .CW x[l..u] .
1404: The function
1405: .CW draw
1406: represents the numbers to be sorted as vertical lines.
1407: The
1408: .CW BEGIN
1409: block sets
1410: .CW n ,
1411: initializes the array,
1412: draws the initial representation,
1413: and then calls a sort routine.
1414: As it stands, the code depicts a 50-element quicksort.
1415: .PP
1416: Some algorithm animation systems present races of programs
1417: by implementing a simple form of time slicing.
1418: To create a race in our system, we first ran the program into the file
1419: .CW qs.s .
1420: We then changed the final line in the
1421: .CW BEGIN
1422: section to call
1423: .CW isort ,
1424: and ran that into the file
1425: .CW is.s .
1426: Finally, we merged the two scripts into one with this
1427: .I awk
1428: program:
1429: .P1
1430: .get race.splice
1431: .P2
1432: The loop copies the script of insertion sort until it encounters a
1433: .CW click
1434: .CW comp
1435: statement; it then copies quicksort until it encounters the corresponding
1436: .CW click ,
1437: at which points it prints the
1438: .CW click
1439: statement.
1440: The variables
1441: .CW s1
1442: and
1443: .CW s2
1444: store the status of the most recent
1445: .CW getline s
1446: of the two files; the status is one if a record was found and
1447: zero if an end-of-file was encountered.
1448: When one file is exhausted, the remainder of the other is copied.
1449: (A production splicer should
1450: have a more graceful interface for naming the files and views.)
1451: .PP
1452: The resulting script file is an execution of the
1453: sorts in two parallel views, synchronized by comparisons:
1454: .INCLUDE race
1455: As before, insertion sort sifts each element into place in turn.
1456: This picture only hints at the operation of quicksort;
1457: insight into that algorithm requires the identification
1458: of interesting events beyond comparisons and swaps.
1459: Quicksort finishes after 240 comparisons, while insertion
1460: sort takes almost three times as long.
1461: For completeness, here is the
1462: .I stills
1463: input that produced the picture:
1464: .P1
1465: .get race.t
1466: .P2
1467: .sp 1
1468: .LP
1469: .I "Trees."
1470: .PP
1471: Here are pictures of a (nonbalanced) binary search tree after inserting
1472: 5, 10, 15 and 20 random integers in the range 0..999:
1473: .INCLUDE bst
1474: In the last two frames, the labels for node 3
1475: and 13 are squeezed too close together.
1476: The script was generated by this
1477: .I awk
1478: program:
1479: .P1
1480: .get bst.gen
1481: .P2
1482: The animation code consists of just three lines in the
1483: .CW insert
1484: procedure.
1485: .PP
1486: The pictures give insight into random binary search trees
1487: in spite of being rather ugly.
1488: The trees have two distinct failings: the depiction of
1489: individual nodes, and the layout of the entire tree.
1490: .PP
1491: A node is represented by its numeric value;
1492: each node is connected to its parent.
1493: If the shape of the tree is more important than
1494: the values it contains, one can delete the values entirely.
1495: We will shortly see a tree with more graceful edges.
1496: .PP
1497: The other aesthetic issue is the layout of the tree.
1498: The @y@-value is the depth of the node in the tree,
1499: which is a very robust choice
1500: (one could also use the time at which the node was inserted).
1501: The @x@-value in this example is simply the randomly generated value itself;
1502: there are many alternative choices.
1503: One could instead use the number of the node in an inorder traversal,
1504: which involves a multiple-pass algorithm:
1505: the tree is first built, then traversed and numbered, and the
1506: insertions are then reported with knowledge of the numbers.
1507: For this representation, it is crucial to separate the
1508: interesting events from their geometric representation;
1509: it is convenient to calculate these in two filters in a pipeline.
1510: .PP
1511: This animation of heapsort uses an alternative representation of trees.
1512: It was generated by a 50-line
1513: .I awk
1514: program.
1515: .INCLUDE heap
1516: Each snapshot shows the result of a
1517: .CW sift
1518: operation.
1519: The first four
1520: .CW sift s
1521: build the heap; subsequent
1522: .CW sift s
1523: maintain the unsorted elements as a heap.
1524: Arrows point from lesser elements to greater elements.
1525: .PP
1526: A node in the heap is represented by its value;
1527: lines between nodes have a single arrowhead and
1528: are chopped by twenty percent at each end.
1529: The root of the heap is at @(1/2,~-1)@,
1530: its two children are at @(1/4,~-2)@ and @(3/4, ~-2)@, their four
1531: children are at @(1/8,~-3)@, @(3/8,~-3)@, @(5/8,~-3)@, @(7/8,~-3)@, etc.
1532: .PP
1533: Other tree layouts proved useful in animating
1534: two algorithms dealing with parse trees.
1535: In both cases, a node's @x@-value was the minimum of the
1536: @x@-values among the node's descendants (equivalently,
1537: the @x@-value of its leftmost child); all edges were therefore
1538: either vertical or slanting down to the right.
1539: A random sentence generator built the tree left-to-right and top-down;
1540: just as in the binary search tree,
1541: the height of a node was one less than its parent.
1542: A parser built the tree in postorder and bottom-up:
1543: the height of a node was one greater than the
1544: maximum of the heights of its children.
1545: .sp 1
1546: .LP
1547: .I "A Graph Algorithm."
1548: .PP
1549: Prim's algorithm for computing the minimum spanning tree (MST)
1550: of a graph starts with a fragment consisting of a single vertex.
1551: It increases the fragment by adding the nearest vertex until all
1552: vertices are in the fragment, at which point it is the MST
1553: of the entire graph.
1554: This picture shows Prim's algorithm on the complete
1555: graph induced by a set of 50 planar points;
1556: the weight of an edge between two points is
1557: defined to be their Euclidean distance.
1558: .INCLUDE mst2
1559: The snapshots are taken every ten stages.
1560: .PP
1561: The obvious implementation of Prim's algorithm on an @N@-point
1562: set requires time proportional to @N sup 3@.
1563: Dijkstra discovered an elegant implementation of the algorithm
1564: with running time proportional to @N sup 2@:
1565: every point not in the fragment keeps a pointer
1566: to its nearest neighbor in the fragment.
1567: Here is Dijkstra's implementation on a ten-node planar graph:
1568: .INCLUDE mst1
1569: In this animation, nodes in the fragment are bullets, nodes
1570: not in the fragment are crosses, edges in the MST are
1571: .CW fat
1572: lines, and the nearest neighbors are pointed to by arrows.
1573: .PP
1574: These two sequences illustrate two
1575: styles of drawing graphs with our system.
1576: Dots and lines are sufficient for simple algorithms,
1577: while various symbols and line options can depict subtle processes.
1578: .PP
1579: The geometric nature of the above graphs made them easy to lay out.
1580: Laying out a general graph is very hard.
1581: If the graphs in your applications are specialized (such as trees),
1582: you might exploit that structure to compute an effective layout.
1583: A graph of @N@ vertices can be easily represented
1584: by an @N times N@ matrix in which the @i,j@-th element
1585: represents the edge from vertex @i@ to vertex @j@;
1586: that is useful for insight into some graph algorithms.
1587: If you have access to a program that produces good layouts of general graphs,
1588: you might use that program to compute positions of vertices,
1589: and then feed those into our system.
1590: .sp 1
1591: .LP
1592: .I "A Memory Allocator."
1593: .PP
1594: The
1595: .I develop
1596: program uses the
1597: .I malloc
1598: memory allocator for several of its data structures.
1599: We augmented
1600: .I develop 's
1601: calls to the allocator with data gathering
1602: routines to produce an animation;
1603: here is the final snapshot.
1604: .KF
1605: .INCLUDE malloc
1606: .KE
1607: The left frame is the arena of storage from which memory is allocated.
1608: Memory blocks are represented by lines,
1609: low addresses are at the bottom of the picture, and
1610: the picture is 1024 bytes wide.
1611: The right frame is a histogram of the sizes of memory currently
1612: allocated; there is a dot for each element, a vertical bar every ten
1613: positions to help counting, and the maximum value is in the lower right corner.
1614: .PP
1615: This snapshot was taken at the end of execution of
1616: .I fdevelop .
1617: The histogram shows two large blocks
1618: of 20,000 and 40,000 bytes, 96 blocks of size 16, and 96
1619: slightly larger blocks (the blocks of size 16 are symbol table records;
1620: each points to an allocated string).
1621: The arena shows the two huge pieces (the larger is higher)
1622: and a gap above the smaller (memory allocated by
1623: procedures that didn't call our augmented
1624: .I malloc ).
1625: The remainder of the arena is allocated efficiently.
1626: .PP
1627: A movie like this helped us find a bug in
1628: .I fdevelop :
1629: an early version allocated the symbol table nodes but did not
1630: .I free
1631: them.
1632: This problem manifested itself in an overloaded arena and a huge
1633: spike in the histogram at size 16.
1634: .PP
1635: The
1636: .I fdevelop
1637: program interacts with the storage allocator only through
1638: the two routines
1639: .I emalloc
1640: and
1641: .I efree .
1642: We animated the storage allocator by modifying those routines:
1643: .P1
1644: .get malloc.c
1645: .P2
1646: They write on the named file output lines of two types:
1647: .P1
1648: m @address@ @length@
1649: f @address@
1650: .P2
1651: The first line denotes that a
1652: .I malloc
1653: of the given length returned the given address;
1654: the second marks a
1655: .I free .
1656: .PP
1657: The resulting history file contains the interesting events;
1658: they are given a geometric interpretation by a subsequent program.
1659: Here is a simple program that generates only the arena view
1660: from the script file:
1661: .P1
1662: .get malloc.awk
1663: .P2
1664: The
1665: .CW BEGIN
1666: block initializes variables,
1667: the actions for
1668: .CW m
1669: lines draw memory, and those for
1670: .CW f
1671: lines erase memory.
1672: The variable
1673: .CW s
1674: is the starting byte of a block;
1675: .CW e
1676: is the ending block.
1677: The variables
1678: .CW sx
1679: and
1680: .CW sy
1681: are the @x@ and @y@ positions of the starting byte, and
1682: similarly for
1683: .CW ex
1684: and
1685: .CW ey .
1686: If the block fits on one line, then only a single line fragment
1687: need be drawn; otherwise, fragments of three types are needed.
1688: .PP
1689: The complete program for generating scripts
1690: from history files is 56 lines of
1691: .I awk .
1692: To ease tracing the action in the arena, it marks a
1693: .I malloc
1694: with an
1695: .CW x
1696: and a
1697: .I free
1698: with an
1699: .CW o .
1700: The histogram view is embellished with bars and the maximum value.
1701: There is room for further elaborations;
1702: one might, for instance, want to put either or both of
1703: the axes of the histogram on logarithmic scales.
1704: .sp 1
1705: .LP
1706: .I "Dynamic Statistical Displays."
1707: .PP
1708: Rick Becker constructed this display of air pollution
1709: in the Northeast United States:
1710: .INCLUDE ozone
1711: The data was gathered hourly on
1712: a single summer day in the early 1970's.
1713: The radius of each circle is proportional to the ozone
1714: reading (a common measurement of air pollution)
1715: at one of 32 stations in New Jersey,
1716: New York, Connecticut, and Massachusetts.
1717: The radius of the clock denotes the maximum ozone level prescribed
1718: by the Environmental Protection Agency;
1719: its hour hand goes from 7:00 AM to midnight.
1720: .PP
1721: This display shows how New York City's
1722: air pollution is blown to the northeast.
1723: Becker and his colleagues prepared a similar movie in the
1724: early 1970's using the technology of the day;
1725: it required several weeks of programming time, then
1726: a weekend with a movie camera to make the final film.
1727: He built this display from the same data in a couple of hours,
1728: then prepared a video tape of the
1729: resulting movie in under thirty minutes.
1730: The original movie was a bit nicer (it drew the background
1731: map and the circles in two different colors),
1732: but the new movie is just as useful, and provides stills for free.
1733: ......
1734: .NH
1735: Living With The System
1736: .PP
1737: The system that we have described is the
1738: bare bones of an animation environment.
1739: We have found that the most fruitful way of enhancing the
1740: environment is not by modifying the primary programs,
1741: but rather by using small filters that interact with the
1742: various files in the system.
1743: .PP
1744: We showed earlier, for instance, a race of two sorting algorithms.
1745: While other animation systems implement races with
1746: a general mechanism for time sharing,
1747: we did the job with a small
1748: .I awk
1749: program that merges two files.
1750: Our system does not have a facility for counting clicks;
1751: rather, we use filters such as
1752: .P1
1753: grep 'click comps' | wc
1754: .P2
1755: to see how many comparisons were made.
1756: We will even admit to using text editors to make minor changes
1757: to both script and intermediate files.
1758: .PP
1759: We have built several useful filters in addition to
1760: .I merge .
1761: The program
1762: .I view.clicks
1763: prints a summary of the views and clicks used in a script file;
1764: it is helpful as one is preparing a
1765: .I stills
1766: file.
1767: Its implementation uses the intermediate file described
1768: in Appendix I:
1769: .P1
1770: .get view.clicks
1771: .P2
1772: The first step of the shell script is to develop the script file;
1773: the subsequent
1774: .I awk
1775: program then reads the resulting intermediate file.
1776: The first pattern/action pair prints for each view its
1777: name and the @x@ and @y@ ranges in the script file.
1778: The second pair builds a string of all clicks from the
1779: define click statements, and the third pair prints that
1780: string and exits at the first non-define statement.
1781: .PP
1782: The program
1783: .I show.clicks
1784: takes a script file as input;
1785: its output is a new script file containing all information in
1786: the input and, in addition, a new view named
1787: .CW click.count
1788: in which the various clicks are counted.
1789: This is useful for preparing
1790: .I stills
1791: files and for debugging.
1792: Its input is a script file,
1793: either named explicitly or as the standard input.
1794: Here is the code:
1795: .P1
1796: .get show.clicks
1797: .P2
1798: The second pattern/action pair stores the name of the current view,
1799: and the fourth action copies each line onto the output file.
1800: The first pattern/action pair supplies a default view name, if needed.
1801: .PP
1802: The work is done when the third pattern recognizes a
1803: .CW click
1804: statement.
1805: The
1806: .CW if
1807: statement puts the click name in
1808: .CW cname ,
1809: and the
1810: .CW print
1811: statement switches to the new view.
1812: The second
1813: .CW if
1814: statement is executed when a new
1815: .CW click
1816: statement is seen; it assigns it a number and prints out the
1817: click name, once and for all.
1818: The two following statements rewrite the appropriate count
1819: and place a bullet next to it.
1820: The final statement returns to the current view.
1821: .PP
1822: One can use the ideas in
1823: .I show.clicks
1824: to process lines in the script file of the form
1825: .P1
1826: @name@ = @value@
1827: .P2
1828: The output script file has a new view named
1829: .CW variables ;
1830: it contains the name of each variable mentioned and its current value.
1831: .PP
1832: Larger filters have also proven useful.
1833: For instance, we built a set of tools to render animations
1834: of three-dimensional lines and text
1835: (circles and rectangles were not supported).
1836: The primary program translated a three-dimensional script into a
1837: standard script that contained two two-dimensional views for
1838: each three-dimensional view; the resulting
1839: .I movie
1840: and
1841: .I stills
1842: were suitable for viewing with standard stereo viewers.
1843: Support programs included a filter for rotating a view
1844: around a given line.
1845: .PP
1846: The
1847: .I movie
1848: and
1849: .I develop
1850: programs are in fact simple shell scripts that call filter
1851: versions named
1852: .I fmovie
1853: and
1854: .I fdevelop .
1855: You may find it convenient to rewrite those shell scripts for
1856: your environment.
1857: .SH
1858: Acknowledgements
1859: .PP
1860: We are deeply indebted to Howard Trickey;
1861: he gave us invaluable advice for getting a minimal
1862: animation facility working in the Sun environment,
1863: then finished the job properly.
1864: He subsequently made it all work under the X window system.
1865: Andrew Hume and Jane Elliott made possible
1866: our first experiments with animation.
1867: Our early users, Rick Becker and Chris Van Wyk,
1868: gave us bug reports and suggestions for improvements.
1869: Eric Grosse, John Linderman, Doug McIlroy,
1870: Steve Mahaney, Howard Trickey, and Chris Van Wyk
1871: made helpful comments on this paper.
1872: .SH
1873: References
1874: .LP
1875: |reference_placement
1876: .sp 100
1877: .BP
1878: .SH
1879: Appendix I \(em Intermediate Files
1880: .PP
1881: This appendix defines the intermediate files produced by
1882: .I develop .
1883: The files are easier to process than the corresponding script files.
1884: For instance,
1885: names are converted to small integers,
1886: floating point numbers are scaled to integers in 0..9999,
1887: and commands are abbreviated to single letters.
1888: .PP
1889: A line whose first non-blank character is
1890: .CW #
1891: is a comment.
1892: .PP
1893: An intermediate file begins with define statements
1894: that give the names of the views and the clicks:
1895: .P1
1896: d v @vnum@ @viewname@ @minx@ @miny@ @maxx@ @maxy@
1897: d c @cnum@ @clickname@
1898: d p @any@ @text@
1899: d p e
1900: .P2
1901: Fields are separated by tab characters.
1902: Both views and clicks are numbered 0, 1, 2, ....
1903: The four final numbers on a view line tell the
1904: range of the coordinates in the original script file.
1905: A line that begins with
1906: .CW "d p"
1907: is a ``pragma''; both
1908: .I movie
1909: and
1910: .I stills
1911: currently ignore all such lines.
1912: The defines appear at the front of the file in
1913: the order views, clicks, pragmas, then
1914: the ``end of defines'' pragma
1915: .CW "d p e" .
1916: .PP
1917: The geometric commands for lines, boxes, circles and text
1918: are mapped to the following:
1919: .P1
1920: g @slotnum@ l @vnum@ @opts@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@
1921: g @slotnum@ b @vnum@ @opts@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@
1922: g @slotnum@ c @vnum@ @opts@ @x@ @y@ @rad@
1923: g @slotnum@ t @vnum@ @opts@ @x@ @y@ @text@ @string@
1924: .P2
1925: Objects that are never erased have slot number 0;
1926: other objects are placed in ``slots'' that can hold at most one object.
1927: The third field is the type of geometric object;
1928: the fourth field is the view number.
1929: All @x@ and @y@ values are normalized to integers in the range 0..9999.
1930: There is a single separating tab before the (unquoted) text string.
1931: Options are given as a string of characters,
1932: whose length and interpretation are summarized as:
1933: .P1
1934: .ps -2
1935: .vs -3
1936: OBJECT POS NAME ABBREV
1937: text 1 center c
1938: ljust l
1939: rjust r
1940: above a
1941: below b
1942: 2 medium m
1943: small s
1944: big b
1945: bigbig B
1946: line 1 solid s
1947: fat f
1948: fatfat F
1949: dotted o
1950: dashed a
1951: 2 - -
1952: -> >
1953: <- <
1954: <-> x
1955: box 1 nofill n
1956: fill f
1957: circle 1 nofill n
1958: fill f
1959: .vs +3
1960: .ps +2
1961: .P2
1962: For instance, the options for a text string are described
1963: by two characters giving its position and its size;
1964: .CW small
1965: .CW center
1966: text has the option string
1967: .CW cs .
1968: Further options may be added at the right end of the string;
1969: subsequent programs should ignore letters they don't expect.
1970: .PP
1971: A click statement is represented as
1972: .P1
1973: c @cnum@
1974: .P2
1975: .PP
1976: An erase statement is translated into
1977: .P1
1978: e @line@ @repeated@ @here@, @except@ e @italic "for"@ @leading@ g
1979: .P2
1980: A processor may choose to implement this statement using
1981: either the geometric description or the slot number.
1982: .PP
1983: A
1984: .CW clear
1985: statement (which erases all objects in a view)
1986: is translated into a pair of starting and ending ``blank''
1987: commands that bracket a sequence of erase statements:
1988: .P1
1989: b s @vnum@
1990: b e @vnum@
1991: .P2
1992: The erase statements together clear the view.
1993: A processor may choose to implement the
1994: .CW clear
1995: either by ignoring the
1996: .CW b
1997: commands and letting the erase statements
1998: take their course or by explicitly processing the start
1999: command and then ignoring
2000: .CW e
2001: commands until encountering the
2002: .CW "b e"
2003: line.
2004: .PP
2005: As an example, running
2006: .CW develop
2007: on this trivial script file
2008: .P1
2009: line 1 2 3 4
2010: text small above 5 6 "Hello, world."
2011: click stage
2012: clear
2013: .P2
2014: produces this intermediate file:
2015: .P1
2016: d v 0 def.view 1 2 5 6
2017: d c 0 stage
2018: d p e
2019: g 1 l 0 s- 0 0 4999 4999
2020: g 2 t 0 as 9999 9999 Hello, world.
2021: c 0
2022: b s 0
2023: e 1 l 0 s- 0 0 4999 4999
2024: e 2 t 0 as 9999 9999 Hello, world.
2025: b e 0
2026: .P2
2027: .PP
2028: Here is a summary of the commands in the intermediate language:
2029: .P1
2030: # @comment@
2031: b s @vnum@
2032: b e @vnum@
2033: c @cnum@
2034: d v @vnum@ @viewname@ @minx@ @miny@ @maxx@ @maxy@
2035: d c @cnum@ @clickname@
2036: d p @any@ @text@
2037: d p e
2038: e @line@ @repeated@ @here@, @except@ e @italic "for"@ @leading@ g
2039: g @slotnum@ l @vnum@ @opts@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@
2040: g @slotnum@ b @vnum@ @opts@ @x sub 1@ @y sub 1@ @x sub 2@ @y sub 2@
2041: g @slotnum@ c @vnum@ @opts@ @x@ @y@ @rad@
2042: g @slotnum@ t @vnum@ @opts@ @x@ @y@ @text@ @string@
2043: .P2
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.