Chapter 3 

Tools for Interaction -

Object-Oriented Programming

M. Firebaugh 

© Wm. C. Brown Communications, Inc. 

 
I think of a computer display as a window on Alice's Wonderland in which a programmer can depict either objects that obey well-known natural laws or purely imaginary objects that follow laws he has written into his program.
Ivan Sutherland

In the first two chapters we attempted to establish the key role computer graphics plays in helping users visualize their work, and the technological tools which make this visualization possible. In this chapter we jump right in and demonstrate the interactive techniques on which modern computer graphics is based. First, we discuss a programming environment in which we will build our applications. Next, we introduce the concept of graphical objects from an object-oriented programming point of view. Then, event handling techniques are discussed and demonstrated with some simple algorithms. Finally, interactive graphics techniques are surveyed, and an algorithm for one of the more useful techniques is presented.

One definition of computer graphics is the creation and manipulation of graphical objects. While this statement may appear intuitively obvious or even trivial, the essential nature of computer graphics is almost completely determined by the design decisions involved in representing graphical objects and the operations available for their creation and manipulation. The objectives of this chapter are to examine these design issues in detail and to create tools for interaction with graphical objects.
 

Programming Environments

Artificial intelligence research has emphasized the importance of the development environment in the productivity of programmers and system developers. The programming environment is at least as important as language features in determining the quality of code and speed with which it is generated. Elements of a an integrated development environment include:

  • Program hierarchy structure ,
  • Integrated editor with syntax checking,
  • Object-oriented class library,
  • Incremental, high-speed compiler,
  • Powerful debugging tools,
  • Access to Application Programming Interface (API) routines,
  • Online, context sensitive help,
  • Integration with other languages and applications.
  •  

    Several supportive integrated development environments have emerged that provide many or all of these features. We demonstrate several features of one such programming environment, THINK Pascal, manufactured by Symantec, a company with deep roots in the artificial intelligence enterprise.
     

    A Pascal Programming Environment Implementation

    The abstract programming environment concepts summarized above are best understood by observing them in action, that is, by studying an actual implementation. The example environment provides all of the elements of a supportive programming environment listed above. In addition, it includes a number of language extensions such as the object-oriented features of Object Pascal, an object-oriented extension of Standard Pascal. Some of the most important features are now summarized.
     

    Hierarchical Structure

    Among the more useful hierarchical features of this language are projects, units, and libraries. Units and libraries are fairly common Pascal extensions for building modular programs through top-down design. Our model environment adds the project as a hierarchical structure containing the main program and all associated units and libraries. A suggested file structure for the Hierarchical File System on the Macintosh is shown in Figure 3.1.
     

    Figure 3.1
    Overall file structure for the Pascal application folder and the user project folder.  



     

    The Pascal application folder contains the integrated Pascal editor-linker-compiler, libraries, units, and utilities folders as shown in Figure 3.2.
     

    Figure 3.2
    Internal structure of the Pascal folder, showing integrated Pascal editor-linker-compiler (keyboard icon), libraries, and folders containing additional libraries and utilities. 



     

    The Projects folder is a HFS structure containing individual project folders, such as Project1, Project2, and Project3 as shown in Figure 3.3. The contents of a typical project, Project 2, are also shown.

    The project file, Project2.?, is the focus of the programming environment. You can think of the project file as the collection of all the essential elements of your completed programÛthe object code into which your source code is compiled, the library routines called by your program, all units used by your program, and the bookkeeping records indicating how they should all be linked together. The Pascal editor provides a Project menu which contains the following options:

  • New Project,
  • Open Project,
  • Close Project,
  • Add Window,
  • Add File,
  • Remove,
  • Build Library,
  • Build Applications,
  • Remove Objects,
  • Set Project Type,
  • Compile Options,
  • View Options.
  • The Project menu contains the necessary tools for assembling all the elements into a complete, stand-alone program. In addition to standard application programs, special applications programs called desk accessories, device drivers, and code resources may be created by use of the Set Project Type option. The next figure shows the contents of the Project2.? file.
     

    Figure 3.3
    Hierarchical structure of Projects folder. The Project2 folder contains two files: the project file, Project2.? and the source code file, project2.p. Details on their contents are shown in subsequent figures. 

     


    Figure 3.4
    Contents of Project2.? project file. The runtime and interface libraries are listed automatically when a project file is created. The project2.p source file is included by an Add File command. 



     

    The Runtime.lib library contains all standard Pascal routines such as writeln and sqrt. The Interface.lib library contains the "glue code" for all Macintosh Toolbox routines marked [Not in ROM]. Since routines from these two libraries are commonly used in almost all Pascal programs on the Macintosh, they are automatically included in the project file. The project2.p source file is included by an Add File command under the Project menu. Upon compilation the corresponding object code is included and properly linked to the appropriate routines from the libraries and units included in the project file.

    The last element of the hierarchical structure is the Pascal program itself. In Figure 3.5 a simple Pascal program is shown along with the graphics it produced in the Drawing window.

    To summarize the steps required to create and execute a Pascal project:

    1. Create a project folder using the New Folder command under the desktop File menu. Pick a helpful mnemonic, Name.

    2. Enter the Pascal editor/compiler by double clicking on its icon, and create a new project by selecting the New Project command under the Project menu. Use the suggested convention, Name.p, in naming the project file.

    3. Under the editor's File menu, use New to create a source code file for your main program.

    4. Write your program, using the editor, and save it as Name.p.

    5. Use the Add File option under the Project menu to add Name.p to the Name.? project.

    6. Use the Add File option to add any additional required libraries and units to Name.p. Note that the order of appearance of libraries and units follows standard Pascal protocolÛan element must be declared before it is called.

    7. When all program elements have been assembled in the project file, Name.?, use the Run menu to compile, link, and execute it. The three execution options include Go for the fastest execution, Step Into and Step Around for the manual single-step mode, and Trace for a slow-motion, automatic execution.
     


    Figure 3.5
    Source code in project2.p file and resulting graphics in Drawing window. The loop causes ten rectangles to be drawn, each 10 pixels wider and 20 pixels higher than the previous one. The patXor mode causes a color inversion of each pattern as it is painted over by a larger rectangle. 

     

    Integrated Editor

    Pascal programs may be prepared by any editor, but most modern programming environments provide intelligent, integrated editors to simplify the coding phase and assure syntactically correct, properly formatted code. Think Pascal offers the programmer considerable flexibility in designing the pretty-printing style. The Source Options selection under the Edit menu provides four subwindows for customizing Fonts, Keywords, Indentation, and Parameters. The pretty-printing default options produce the output shown in Figure 3.5.

    The intelligent model Pascal editor "knows" Pascal syntax and will flag any deviations from non-standard usage. For instance, if the programmer had forgotten the colon in the Pascal loop in Figure 3.5, the system would ring the bell and display the helpful hint shown in Figure 3.6.
     

    Figure 3.6
    Thumbs down symbol indicating the line containing the error. The highlighted erroneous code follows the missing ":" in the ":=" assignment symbol.  



     

    Such intelligent editors make writing incorrect syntax virtually impossible, but even intelligent editors cannot detect semantic errors (errors in meaning).

    The model Pascal editor is described as integrated because the system includes the linker and compiler in the same application. The user can move smoothly from the editing phase to the compilation phase without ever leaving the program. If an error occurs during compilation, the program "bounces back" to the editing phase for debugging.
     

    Intelligent, High-Speed Compiler

    Think Pascal compiles many thousand lines of code per minute which is faster than most time-shared minicomputers. In addition to its high speed, this Pascal is "intelligent" in keeping track of which routines have been modified since the last compilation and then recompiling and relinking only those routines in which changes have been made.

    Compiler options allow for generation of code for the M68020 (rather than the M68000) and for the MC68881 floating point coprocessor. It also allows for range options on the set of integers. Additional system options are indicated by letter under the Options column in Figure 3.4. This user-controlled option code signifies the following:

    D ÆDebug. Allows stepping, stopping, stack checking, and observing.

    N Æ Names. Insert Macsbug (debugger) names into the code.

    V Æ Integer arithmetic overflow checking.

    R Æ Range checking compiler switches.

    The combination of compilation and runtime options with the high-speed, integrated compiler provides a truly supportive, integrated environment for program development.
     

    Debugging Tools

    The Pascal syntax you generate with the editor is guaranteed to be correct. However, programs may be syntactically correct but still contain semantic errors, that is, errors in logic or meaning. You may mean to do one thing, but the program does something else.

    The easiest semantic errors to detect are runtime errors. These include such common errors as dividing by zero or setting the index of an array dimensioned [1..100] to 101. The model Pascal detects such errors at run time and flags the offending line of code with the "thumbs down" icon. Usually the error indication and line identification is sufficient information for correcting the bug.

    For the most difficult errors, those in which the program runs flawlessly but produces flawed results, the system supplies six powerful debugging tools with which the programmer can rapidly identify and eliminate errors of logic. These include:

  • The Step Into and Step Around command with execution finger - Upon selecting the Step option under the Run menu, an execution finger appears at the starting point in the program (see Figure 3.7). Hitting the appropriate control keys single steps you through the program with the execution finger always pointing at the line about to be executed. Options are available for stepping into or around called functions and procedures. The combination of this mode with observation of the Text and/or Drawing window output is often sufficient for debugging your program.

  • The Trace command with execution finger - This mode closely resembles the Step mode in which the computer, rather than the user, does the stepping. It runs slowly enough that the programmer can follow the control of flow, but  also runs rapidly enough to reduce the tedium of single stepping.

  • Setting break points with Stop Signs and Go-Go - For large programs, both the Step and Trace modes may become slow and awkward. In such cases, you may select the Stops In option under the Debug menu and drag the stop sign icon into your program where ever you wish a break point (see Figure 3.7). Upon running with the Go-Go command, the program will run full speed up to the stop sign and then pause, allowing you to check the value of output and program parameters.

  • Parameter monitoring via the Observe window - The Observe window is the most useful tool for monitoring the value of expressions and variables as the program executes in one of the above three debug modes. One simply selects the Observe item under the Windows menu and an empty Observe window appears. Next, the variables we wish to monitor are entered, one per line. As the program is executed line by line, the present values of the parameters under observation are displayed. Figure 3.8 shows the status of the Observe window after two loops of the for statement. In addition to debugging programs, the Observe window is useful in demonstrating the concept of scope and lifetime of parameters. Scope is the physical extent in a program for which the parameter is defined; lifetime is the temporal duration of a parameter's definition.

  • Modifying parameters with the Instant window - The Instant window enables you to modify any parameter of the program without actually modifying the program itself. If, for instance, we wish to reassign left the value of 50 just before SetRect is called, we open the Instant window, type in the desired code segment as shown in Figure 3.8, and click Do It.



  • Figure 3.7
    Source code window, Observe window, and portion of Drawing window after two executions of the for loop. The Observe window indicates the value of the parameters as the code is executed line by line. The stop sign at SetRect will halt execution at this point in the fullspeed Go mode. 



     


    Figure 3.8
    Modification of code segment to produce a square. Do It is pressed when the pointer is on SetRect. 



     
     
  • Detailed probing of the program with the LightsBug code view debugger - The three debug modes and two debug windows described above are sufficient for detecting the vast majority of program bugs. If, however, a particularly pesky bug requires examining the compiled program at the machine language level, the appropriate tool is the LightsBug debugger. This tool resides under the Windows menu and provides access to all variables, the system registers, the heap zone, memory, and compiled code. The LightsBug window, shown in Figure 3.9, consists of four user-resizable panes for viewing the system status and nine probe tools for selecting and modifying system parameters.
  •  

    Access to High-Level Routines

    More than six hundred routines of the User Interface Toolbox are written in Pascal and readily callable from THINK Pascal. Data types used by the routines are described as Pascal records, pointers, and arrays. The details of their calling sequence and parameter specifications are given in Inside Macintosh. As various routines are required for building graphical applications, they will be listed and demonstrated.
     


    Figure 3.9
    LightsBug debugger window showing panes for viewing the system status and the probe tools for selecting and modifying system parameters. 



     

    We conclude this discussion of integrated development environments by noting that many other excellent programming environments are available. Some of the most noteworthy include UNIX, X Windows, and Turbo Pascal. They all provide powerful editors and debugging tools to facilitate the rapid development of error-free code. Rather than survey the features of all of them, we felt the reader would gain most from the fairly thorough summary of the features of the system used to build graphical objects and introduce graphical algorithms in this chapter.
     
     

    Graphical Objects and OOP

    In the broadest sense, all graphical images are graphical objects. They all share common attributes such as height, width, pixel depth (color resolution), creator, file type (PICT, TIFF, EPS, and so on), and operations to which they respond. The image file structures discussed in the previous chapter specify graphical objects in the traditional procedural programming paradigm. However, graphical objects also provide examples of the techniques and advantages of the more modern object-oriented programming (OOP) paradigm. Consider the following OOP concepts and their icon-based, graphical user interface representations (GUIs).
     

    Object-Oriented Programming Concepts

    Graphical user interface design rests firmly on the foundation of OOP and illustrates its power and elegance. Some of the most important OOP concepts are listed below.

  • Objects - These are defined as data and the closely associated actions which operate on the data. This integration of data and operations into a single object is called encapsulation. In GUI design, objects are abstracted as icons and menus which represent folders, files, application programs, processes, and operations.

  • Messages - These are defined as the requests sent to an object to execute the actions of which it is capable. Different objects may support different messages and may respond identically or differently to the same message. In GUI design, messages may be sent by the mouse in performing actions such as selection, launching, copying, restructuring, trashing, and ejecting. Messages commanding actions of saving, duplicating, printing, cutting, copying, and pasting may be sent via either the mouse or keyboard. The same message may cause different actions in different icons -- a single click selects some icons and opens others.

  • Methods - These are the routines and algorithms for implementing messages. In GUI design, methods are implemented by high-level routines supported by the event manager, windows manager, menu manager, and so on.

  • Class hierarchy - Each object belongs to a class and is called an instance of the class. Class hierarchy provides for superclasses and subclasses. All objects of a subclass inherit the data and behavior defined by the superclass of which they are members. The class without a superclass is called the root class. A given class supports certain methods common to all members of the class. In GUI design, classes exist for data files, applications programs, menu headers, and menu selection items.

  • Inheritance - Membership in a class provides inheritance of data and methods for all members of the class. Members of a subclass inherit all the instance variables and methods of its superclass unless it chooses to override them with local variables and/or methods. Inheritance provides advantages of reducing data redundancy and action code duplication. In GUI design, all data icons share the method of examining their own creator slot and searching for the application program it points to when they are opened. However, the subclass of WINGZ data files differs significantly from the subclass of MS-Word data files in its icon style, creator designation, internal file structure and so on.



  • Figure 3.10
    System response when command "trash this application program" is issued with the mouse by dragging its icon to the trash can. To suppress this warning, the Option key may be pressed during the drag command.  



     
  • Polymorphism - Literally multiple forms, this feature of OOP means that the same message may be sent to objects of different classes. The response from members of distinct classes may be identical to, similar to, or completely distinct from each other, depending on the method chosen by each class for implementing the message. In GUI design, for instance, all members of the data file class may meekly vanish without trace when dragged to the trash can, whereas icons from the more important application program class will bravely challenge the user with the warning shown in Figure 3.10, and disk icons will interpret the same message as "eject yourself."
  • Computer graphics has served as the test bed for many of the original OOP concepts. SmallTalk, the seminal OOP language, was written at Xerox PARC, the origin of the WIMP GUI. It should not come as a surprise to students of computer graphics that the most successful GUIs rely most heavily on OOP. We shall find OOP concepts helpful and natural tools for developing graphics algorithms throughout the remainder of this book.
     

    Graphical Object Types

    Just as with other complex data structures, graphical objects may themselves be composed of more elementary graphical objects. A useful analysis of graphical objects can be made in terms of their type and hierarchical structure. A straightforward classification of graphical object types may be given as:

  • Primitive objects - Single QuickDraw routine calls,

  • Complex objects - Composite of primitives,

  • Undifferentiated objects - Pixel level information.
  • Consider these in more detail.

    Table 3.1
    Graphics Primitives - Pens, Points, and Lines
    Object
    Pascal Syntax
    Example Call
    Description
    Pen
    Procedure PenSize( width, height:INTEGER);  PenSize(2,2); Sets the size of the plotting pen, in pixels 
    Pen- move
    absolute
    Procedure MoveTo(h,v: INTEGER);  MoveTo(100,50); Moves pen (invisibly) to pixel (h,v) (absolute coordinates) 
    Pen- move
    relative
    Procedure Move(dh,dv: INTEGER);  Move(10,10); Moves pen (invisibly) dh pixels horizontally and dv pixels vertically (relative coordinates) 
    Point
    Procedure DrawLine(x1,y1, x1,y1:INTEGER);  DrawLine(50,100,50,100);  Draws a line from point (x1,y1) to the second point, (x1,y1), i.e. a point 
    Point
    Procedure MoveTo(x1,y1: INTEGER);  

    Procedure LineTo(x1,y1: INTEGER); 

    MoveTo(50,100);  

    LineTo(50,100); 

    Moves to pixel (x1,y1) and draws a line to (x1,y1), i.e. a point 
    Point
    Procedure Line(dx,dy: INTEGER);  Line(0,0); From the present position of the pen, draw a line a distance (0,0) 
    Line -
    absolute
    Procedure DrawLine(x1,y1, x2,y2:INTEGER);  DrawLine(50,100,200,300);  Draws a line from point (x1,y1) to the second point, (x2,y2) 
    Line - 
    absolute 
    Procedure MoveTo(x1,y1: INTEGER);  

    Procedure LineTo(x2,y2: INTEGER); 

    MoveTo(50,100);  

    LineTo(200,300); 

    Moves to pixel (x1,y1) and draws a line to (x2,y2) 
    Line - 
    relative
    Procedure Line(dx,dy: INTEGER);  Line(100,200); Draw a line a distance (dx,dy) relative to the present pen position 
    Text 
    Procedure WriteDraw(p1 [,p2Ö, pn]);  WriteDraw(ÎPen at:',x,y);  The WriteLn equivalent procedure for the drawing window 
    Drawing Window
    Procedure ShowDrawing;  ShowDrawing; Opens the Drawing Window 



    Primitive Objects - Pens, Points, and Lines

    In principle, the only absolutely essential graphics primitive, assuming a raster display is a routine to draw a point at pixel (x,y). Algorithms exist for constructing lines and curves from points. Routines for more complex figures are easily built from the line and curve routines. However, almost all languages support graphical routines for constructing primitive objects at least as complex as rectangles and ovals.

    The most elementary Pascal primitive objects and their calling sequence are the pens, points, and lines shown in Table 3.1.

    These elementary graphics functions are sufficient for writing our first complete Pascal program, Primitives. In Primitives, three different procedures are used for drawing three different sized points. Then, three different procedures are used for drawing three lines of different widths. All points and lines are labeled using the WriteDraw command, the Drawing window equivalent to WriteLn.
     

    Pascal Program Primitives


    program Primitives;
    {Program to demonstrate Pascal point & line primitives.}

    begin

    ShowDrawing; {Opens Drawing Window}

    {First draw three points by three different functions}

    PenSize(1, 1); {Sets pen size to 1 x 1 pixels}
    DrawLine(50, 50, 50, 50);
    WriteDraw(' Point at (50,50) using DrawLine');

    PenSize(2, 2);
    MoveTo(100, 75); {Absolute move}
    LineTo(100, 75);
    WriteDraw(' Point at (100,75) using LineTo');

    PenSize(3, 3);
    MoveTo(150, 100); {Absolute move}
    Line(0, 0);
    WriteDraw(' Point at (150,100) using Line');

    {Now Draw three lines by three different functions}

    MoveTo(150, 175); {Absolute move}
    WriteDraw('Line drawn with DrawLine');
    DrawLine(150, 125, 50, 225);

    PenSize(2, 2);
    Move(0, 25); {Relative move}
    LineTo(150, 250);
    WriteDraw('Line drawn by LineTo');

    Pensize(1, 1);
    Move(0, 25); {Relative move}
    Line(-100, 50);
    WriteDraw('Line drawn by Line');

    end.

    The output generated by running Primitives is shown in Figure 3.11.

    A close examination of Figure 3.11 reveals several features of THINK Pascal graphics on the Macintosh.

  • The unit of measure is the pixel. This is the "natural" unit corresponding to the smallest addressable object on the screen.

  • Pixels are square. On the Macintosh, each pixel is approximately 1/72 inch on a side, equivalent to one point in typesetting notation. This fortunate choice of pixel dimension has simplified the tasks surrounding typesetting and avoids the complexity of aspect ratios inherent in the nonsquare pixels used by many other display devices.

  • The coordinate system is local to the Drawing window, that is, pixel measurements are made relative to the window rather than the overall display screen. This OOP feature greatly simplifies the task of locating the image within the window -- in OOP language all objects in the window are subclasses of the window object and inherit its coordinate system.

  • The origin of the coordinate system is located at the upper left corner, with increasing x measured to the right and increasing y measured downward. While this seems to go against our intuition, it conforms closely to the format for scanning the CRT screen and for writing text to a page. The task of memory-mapping images to the screen is greatly simplified by adopting this protocol, and, as a result, it has become the standard for most graphics systems.

  • Both absolute and relative pen-move and line commands are supported. Absolute commands refer to actual pixel coordinates, (x,y). Relative commands refer to incremental motions, (dx,dy), relative to the present pen position.

  • The output line generated by the WriteDraw command begins at the present pen position which is at the lower left-hand corner of the message. Judicious use of WriteDraw for labeling graphics output is valuable to programmer and user alike in interpreting graphical output.

  • Although pens, points and lines are the most elementary of all graphical objects, they form the basis for much more complex objects. For many applications they provide the natural building block object for constructing intricate and complex patterns. Consider, for instance, the program, Pattern, which uses the relative line function, line(x,y), in a recursive function, Spiral, to draw a square, spiral pattern.



    Figure 3.11
    Output generated by Primitives program. 






    Figure 3.12
    Output of recursive spiral generator. The main program moves the pen to (20,20) and then calls Spiral which continues to call itself, plotting as it shrinks to nothing. It halts when the relative moves in both x and y fall below 10 pixels. 





    The basic algorithm of Pattern can be stated as:

    1. Move to the starting point,

    2. Draw a line relative to this point,

    3. Shorten the relative line ,

    4. Turn 90_ to the right by a combination of x¥ y exchanges and sign changes,

    5. Repeat from step 2, using recursion, until the relative move size drops below some threshold.

    In systems supporting Turtle Graphics from the LOGO language, the Pattern program could be reduced to a tight, recursive loop containing two commands, right(90) and move(r-5). In whatever language, however, it is clear that a line command is the natural and essential command for creating such patterns.


    Pascal Program Pattern


    program Pattern;

    {Program to build spiral pattern, using}
    {relative line routine in a recursive loop}

    procedure Spiral (x, y, sign: integer);
    {Procedure to spiral into limbo}
    var
    temp: integer;
    begin

    sign := (-1) * sign;
    if (abs(x) < 10) and (abs(y) < 10) then
    halt {Done recurring - ground case}
    else {Spiral still sizable}
    begin
    line(x, y); {Plot relative line}
    {Reduce magnitude of relative move by 5 pixels}
    if abs(x) > abs(y) then
    x := x - (x div abs(x) * 5)
    else
    y := y - (y div abs(y) * 5);
    {Exchange x<--> y}
    temp := x;
    x := y;
    y := temp;
    {On even calls, change sign}

    x := sign * x;
    y := sign * y;
    Spiral(x, y, sign); {Recur}
    end;

    end;

    begin

    sign:=1;
    ShowDrawing;
    MoveTo(20, 20);
    Spiral(200, 0, -1);
    end.



    The second program illustrates an algorithm in which the natural object is a point. Consider the Fractal program which implements the "Chaos Game" algorithm for constructing the Sierpinski fractal shown in Figure 3.13.


    Pascal Program Fractal


    program Fractal;

    {Program to play the Chaos Game }

    {Algorithm: }
    { 1. Pick a point in a triangle at random & plot it }
    { 2. Pick a vertex of the triangle at random }
    { 3. Move 1/2 way from present point to this vertex }
    { 4. Plot point and loop from (2) until mouse pressed.}

    var
    xp, yp, i: integer;
    x, y: array[1..3] of real;

    function Rndint (n: integer): integer;
    {Function to return random integer on range 1 --> n}
    var
    rr: longint;
    r: real;
    begin

    rr := random; {Intrinsic routine}
    r := (rr + 32767) / (32767 + 32768);
    Rndint := trunc(n * r) + 1;
    end;

    begin

    ShowDrawing;
    {Set corners of triangle centered at (110,125),}
    {with sides 200 pixels long}
    x[1] := 110 - 100;
    y[1] := 125 + 57.73503;
    x[2] := 110;
    y[2] := 125 - 115.470;
    x[3] := 110 + 100;
    y[3] := y[1];
    {Pick first point at random in box containing triangle}
    xp := Rndint(200) + 10;
    yp := Rndint(173) + 10;
    DrawLine(xp, yp, xp, yp); {Plot point}

    repeat {until Mouse button is pressed}
    i := Rndint(3); {Pick random corner}
    xp := round((x[i] - xp) / 2 + xp); {Go half way}
    yp := round((y[i] - yp) / 2 + yp); {Go half way}
    DrawLine(xp, yp, xp, yp); {Plot point}
    until button;

    end.




    The Chaos Game algorithm is described in detail by Barnsley and his co-workers. Two features introduced in this program include:

  • The use of the system routine, Random, which returns an integer in the range from -32768 through 32767 to build a more useful function, RndInt(n), which returns a pseudo-random integer on the range 1 Æ n. This process of giving an object a name and generalizing it is called abstraction.

  • The use of interactive programming for program control. The intrinsic Button procedure remains false until the mouse button is pressed at which point it becomes true.



  • Figure 3.13
    Output of Fractal program. This pattern demonstrates self-similarity and scaling (no atomic size) which are features of fractal objects. It is remarkable that an iterative, random-number-based algorithm can generate such a symmetric and regular object. 



     

    Primitive Objects - Geometric Figures

    The next level in data abstraction is the definition of common geometric objects - squares, rectangles, rounded rectangles, circles, ovals, arcs, and wedges. All seven of these geometric objects may be considered special instances of the four basic QuickDraw objects: Rectangles, Ovals, Rounded-Corner Rectangles, and Arcs. These four QuickDraw objects are all based on the special data type, Rect, consisting of the four integers, left, top, right, and bottom defining the bounding-box containing the object. Messages are sent to the bounding-box rectangles by a set of ten rectangle manipulation procedures, including SetRect, OffsetRect, UnionRect, EqualRect, and EmptyRect. Each of the QuickDraw object types has a standard set of messages to which it responds. Table 3.2 presents a summary of the Messages/Objects procedures available for geometric figures.


    Table 3.2
    Graphics Primitives - Geometric Figures
    ObjectÆ
    ØMessage
    Rectangles
    (Squares)
    Ovals
    (Circles)
    Rounded-Corner
    Rectangles
    Arcs and
    Wedges
    Frame
    Procedure  

    FrameRect(r:Rect) 

    Procedure  

    FrameOval(r:Rect) 

    Procedure Frame Round Rect (r:Rect; oval Width, ovalHeight:Integer)  Procedure FrameArc (r:Rect;startAngle, arcAngle:Integer) 
    Paint
    Procedure  

    PaintRect(r:Rect) 

    Procedure  

    PaintOval(r:Rect) 

    Procedure Paint Round Rect(r:Rect; oval Width, ovalHeight:Integer)  Procedure PaintArc (r:Rect;startAngle, arcAngle:Integer) 
    Erase
    Procedure  

    EraseRect(r:Rect) 

    Procedure  

    EraseOval(r:Rect) 

    Procedure Erase Round Rect(r:Rect; oval Width, ovalHeight:Integer)  Procedure EraseArc (r:Rect;startAngle, arcAngle:Integer) 
    Invert
    Procedure  

    InvertRect(r:Rect) 

    Procedure  

    InvertOval(r:Rect) 

    Procedure Invert Round Rect(r:Rect; oval Width, ovalHeight:Integer)  Procedure InvertArc (r:Rect;startAngle, arcAngle:Integer) 
    Fill
    Procedure  

    FillRect(r:Rect;  
    pat:Pattern) 

    Procedure  

    FillOval(r:Rect;  
    pat:Pattern) 

    Procedure FillRound Rect(r:Rect; ovalWidth, ovalHeight:Integer;  
    pat:Pattern) 
    Procedure FillArc (r:Rect;startAngle, arcAngle:Integer;  
    pat:Pattern) 



    These procedures will be demonstrated in the program GeomFig. While the procedure names and arguments are fairly obvious from their mnemonics, the following clarifications may be helpful:

  • Bounding boxes are defined with the SetRect procedure whose syntax is:
  • procedure SetRect( var r:Rect;left,top,right,bottom:integer);

    To build a 200 x 100 pixel shoe box called box1, whose upper left-hand corner was located at (50,50), we would make the procedural call:

    SetRect(box1,50,50,250,150);

  • The default value of the pen pattern is black, but at any point in the program a new pattern may be defined and used in subsequent messages. This is particularly useful for the filling commands. The syntax for setting a pen pattern is given as:
  • procedure PenPat(pat:Pattern);

    Predefined choice of patterns include: white, black, gray, ltGray, and dkGray. To redefine the pattern, we would call:

    PenPat(gray);
  • The Rect bounding box for defining ovals specifies the boundary within which the oval is inscribed. To draw a circle, for instance, one specifies a square Rect.

  • The ovalWidth and ovalHeight used in defining rounded-corner rectangles are simply dimensions in pixels of the ovals which specify the shape of the corners of the rounded-corner rectangles.

  • The startAngle and arcAngle parameters used in defining arcs and wedges specify exactly what their names imply, with angles measured in degrees.
  •  

    With this background, let's build the program GeomFig to demonstrate the response of each of these object types as it receives various messages.
     

    Pascal Program GeomFig 


    program GeomFig;

    {Program to build each of the four basic geometric figures: }

    { rectangle }
    { oval }
    { rounded-corner rectangle }
    { arc }

    {and demonstrate the five messages to which these objects respond: }

    { Frame, Paint, Erase, Invert, and Fill. }

    var
    windowBox, rectBox, ovalBox, rcBox, arcBox: Rect;
    row, col, dh, dv, A: integer;

    begin

    {First, define the Drawing Window for a large screen Mac}
    SetRect(windowBox, 400, 100, 832, 604); {A 6" x 7" window}

    SetDrawingRect(windowBox);
    ShowDrawing;
     

    {Next, use FrameRect in a loop to draw frames for subsequent figures}

    setRect(rectBox, 18, 18, 196, 160);
    PenSize(2, 2);
    dv := 0;
    dh := 0;
    for col := 0 to 1 do
    begin
    for row := 0 to 2 do
    begin
    OffsetRect(rectBox, dh, dv);
    FrameRect(rectBox);
    dv := 160;
    end;
    OffsetRect(rectBox, 200, (-2 * 160));
    dv := 0;
    end;

    {Paint a square in the upper left frame}
    SetRect(rectBox, 65, 40, 145, 120);
    PaintRect(rectBox);
    MoveTo(45, 150);
    WriteDraw('A Paint Message to a Square');

    {Draw an oval frame in the upper right frame}
    setRect(ovalBox, 240, 30, 380, 130);
    PenSize(8, 3);
    FrameOval(ovalBox);
    MoveTo(245, 150);
    WriteDraw('A Frame Message to an Oval');

    {Draw a circle and paint it gray}
    setRect(ovalBox, 55, 190, 155, 290);
    PenPat(Gray);
    PaintOval(ovalBox);
    MoveTo(45, 310);
    WriteDraw('A Paint Message to a Circle');

    {Draw a Rounded-Corner Rectangle and fill it with ltGray}

    setRect(rcBox, 240, 190, 380, 290);

    PenSize(10, 10);
    PenPat(Black);
    FillRoundRect(rcBox, 40, 30, ltGray);
    FrameRoundRect(rcBox, 40, 30);
    MoveTo(227, 310);
    WriteDraw('A Fill/Frame Message to a Rnd-Rect');

    {Draw a 270_ arc}
    setRect(arcBox, 40, 355, 170, 445);
    PenSize(1, 1);
    FrameArc(arcBox, 0, 270);
    MoveTo(45, 470);
    WriteDraw('A Frame Message to an Arc');

    {Draw a Pie-Chart from wedges}
    setRect(arcBox, 255, 350, 355, 450);
    PenSize(2, 2);
    A := 15;
    FillArc(arcBox, A, A, White);
    FillArc(arcBox, 2 * A, 2 * A, dkGray);
    FillArc(arcBox, 4 * A, 4 * A, ltGray);
    FillArc(arcBox, 8 * A, 8 * A, Black);
    FillArc(arcBox, 16 * A, 9 * A, Gray);
    InvertArc(arcBox, 12 * A, A);
    EraseArc(arcBox, 20 * A, 2 * a);
    FrameArc(arcBox, 0, 360);
    MoveTo(245, 470);
    WriteDraw('Fill Messages to Wedges');

    end.

    The GeomFig program demonstrates a number of interesting features. First is that the increased abstraction achieved by named objects with attributes and methods results in increased programming power and expressiveness. Each of the six frames in Figure 3.14 required 5-6 commands on the average. To achieve the same results using more primitive point and line commands would have required several times as much code.

    The second observation is that reasonably complex graphics (e.g., the frame rectangles and piecharts) are readily produced by variations on these geometric primitives.

    Higher-level graphical languages like PHIGS and FIGS extend the concept of abstraction by providing routines for manipulating 3D objects. Most toolkits like TurboPascal for Windows and the Macintosh QuickDraw routines are limited to 2D objects and manipulations.


    Figure 3.14
    Output from GeomFig program. The program displays seven geometric objects (rectangle, square, oval, circle, rounded-rectangle, arc, and wedge) through five messages sent to four object types (Rectangle, Oval, Rounded-Corner Rectangle, and Arc). 



     

    Interaction Algorithms

    The secret of good graphical user interface design is interactivity. In an application supported by a good GUI, users will frequently find themselves deeply involved in the application and doing productive work before ever touching the keyboard.


    Features of Good GUIs

    There are three indicators of systems with good GUIs and their users.

  • The User Reference Manual for a given application is still shrink-wrapped months after the user has become an expert with the application. All possible program options are instantly available under one or more levels of menu selection, and an encapsulated, context-sensitive Reference Manual in the form of a HELP file is only a button click away.

  • The mouse becomes, in effect, a powerful extension of the user. After a few months of intensive use of a WIMP system, users find themselves frustrated and a bit embarrassed when they try to point at off-screen objects with the mouse cursor which hangs up on the edge of the screen. This is a particularly noticeable phenomena in a large group programming environment in which programmers frequently highlight some program element for their colleagues by pointing at it with the mouse cursor rather than their finger.

  • The measure of a good GUI is the extent to which the user is totally unaware of the system and conscious only of the work. Programs ported over from command-line interface systems are detected instantly (actually, it may take a minute or two), because of their lack of a good GUI.
  • Now that we have become acquainted with graphics primitives such as points, lines, and geometric objects, the only missing ingredient we must explore before we begin building interactive graphics user interfaces is a set of event handling routines. While Standard Pascal does not support interactive graphics, most of the extended Pascal dialects do include routines for sensing mouse cursor position and detecting events such as button presses. Without such event handling routines, it is virtually impossible to build a good GUI.
     


    On to Lecture 6