COP 2224  C++ Programming

Programming Project #1

(Due Tuesday, October 3, 2000, by the start of Class)

 

Purpose:

To practice basic C++ statements and programming ideas, such as if-statements, loops, simple input and output using the iostream class, and simple class design.  To practice good programming techniques, style, design, testing, and good program documentation, on a small programming example.

 

Background:

For this project you must write an interactive program that enables the user to draw circles and lines on the screen, to erase the screen, and to quit the program.  You must not use extensions to C++ to draw the lines and circles using high-level Borland function calls.  You must figure out how to draw circles and lines yourself (attached are some pseudocode algorithms for drawing lines and circles).  The idea is to have a 2-dimensional array to represent the screen.  You will not be setting pixels (or bits) on the screen directly.  Instead you will set cells in the two dimensional array to certain character values.  For example, you can use a space (or period) to show an empty cell, and an asterisk to show a drawn cell.  (This is the only portable way to do graphics for now.)  After getting each user command and then setting the correct cells of the array to asterisks, the entire array is printed to the screen.  The user is then prompted to enter the next command and the process repeats.

In a GUI program, the object representing the window would update a window on the screen directly, as any changes are made.  Don’t do that for this project!  What we want is the commands the user types to invoke member functions of an object, which in turn update a two dimensional array of char.  The main program then calls display() to refresh the screen.  The point is to have a general purpose class that can be reused for other projects, like a banner program, a game (tic-tac-toe), etc.  The class must be designed from one point of view, then an application is designed (sketch) that uses the class.

If using the new Borland free 5.5 compiler tools, you will need to create a makefile.  (If using Borland C++ or MS Visual C++, you will need to create a project file instead.)  You can download a working executable to play with (containing many "extra" features), plus a working makefile you can use.


Programming Requirements:

Your program must be capable of drawing circles and lines in a 20 row (the “r” dimension) by 72 column (the “c” dimension) grid.  Thus the point r=0, c=0 is at the upper left-hand corner of the screen, the point r=0, c=71 is at the upper right-hand corner, and the point r=19, c=71 is at the lower right-hand corner.

·        Your program should use only iostreams and not stdio for input and output.

·        The program should initially show an empty screen, below which is a prompt for user input.

·        In a professional program the user input would be mouse or menu driven.  To simply the project so you can concentrate on the important details, the legal user input for our project is CLI (Command line Interface) only.  The user must enter one of the following four commands:

1.      line r1  c1  r2  c2
      which draws a line from the point (r1,c1) to the point (r2,c2),

2.      circle r  c  radius
      which draws a circle with the center at point (r,c) and a radius radius,

3.      clear
      which erases the entire image (puts it into the initial state), and

4.      quit
      which exits the program.

·        Illegal input should print a message and redraw the screen (including a new prompt).  It is not illegal to attempt to draw lines and circles that are partially (or wholly) off the screen.  Your program must draw only the parts that will show.  (This is known as scissoring.)

·        You must have a class object that represents the screen (or window), it must include member functions for the following messages (other member functions may be desirable too, it depends on your design):

·        display() which sends the screen to standard output (using streamio)

·        clear() which erases the contents of the array (it does not clear the physical screen!)

·        line() which draws a line of asterisks between two specified points (provided as parameters)

·        circle() which draws a circle of asterisks as a given point with a given radius (provided as parameters)

 

Test Data:

You can (and should!) test your program with many different data sets, not just this one.  If your program includes extra features, make sure to show them off.

 

line 5 5 10 10
line 10 10 5 5
circle 20 35 5
clear
line -5 35 10 100
circle 10 35 6
quit


To be turned in:

A 3.5" disk with your program on it (screen.exe, screen.cpp, screen.h, main.cpp, and makefile).

NOTE: main.cpp has no class definitions in it!

 

Additional Notes:

This program is an example of the singleton design pattern.  You will create a single object of class screen that all functions of your program can access.  Depending on the user input, you will send different messages to the screen object.  This design is very flexible since you can easily add other shapes to your class, or have multiple screen objects.  Note that your class screen will have other member functions than just the four listed above, but they are part of the implementation of class screen so no users of a screen object need ever invoke such functions.  Some obvious choices are to have a function plot(r, c) that actually modifies the two dimensional array of char by setting some cell to '*' (provided r and c are within the bounds of the array), or the circle_pts() function from the pseudocode below.  (Note that plot is defined to use a single point argument. You can redefine functions to use two ints instead.)  If you need any help understanding the graphics algorithms below, or anything else, please don’t hesitate to ask me!


 

Line Drawing Algorithm (in Pseudo C++)

 

// Algorithm from "Principles of Interactive Computer Graphics", 2nd Ed.

// by W. M. Newman and R. F. Sproull, McGraw-Hill, NY, (c)1979.  page 24.

 

 

void plot (Point p)          // This (member?) function plots 1 point

{ if (p is off-screen)

    return;                  // Not an error, so OK to ignore.

  else

    rep[p.r][p.c] = Ink;

}

 

 

 

void draw_line (Point start, Point end)

{ int i, len, len_r, len_c;

  double r, r_inc, c, c_inc;

  if (start == end)          // Plot the single point

  { plot(end);

    return;

  }

  len_r = end.r - start.r;

  len_c = end.c - start.c;

  if (abs(len_r) > abs(len_c))

    len = abs(len_r)

  else

    len = abs(len_c);

  r_inc = len_r / (double) len;

  c_inc = len_c / (double) len;

  r = start.r + 0.5;

  c = start.c + 0.5;

  for (i=0; i<=len; ++i)

  { plot(point(int(r), int(c)));

    r += r_inc;

    c += c_inc;

  }

}


 

Circle Drawing Algorithm (in Pseudo C++)

 

// Algorithm from "Computer Graphics: Principles and Practice", 2nd Ed.

// by J. Foley, A. van Dam, et. al.  Addison-Wesley, (c)1990. pp. 81-ff.

 

// Given one point p on a circle drawn around the origin, and the

// center point c of the circle we really wish to draw, this function

// will draw (by calling "plot()") the eight related point of the circle.

// For example, if the point (1,3) is on the circle, so are the points:

//   (1,3), (1,-3), (-1,3), (-1,-3), (3,1), (3,-1), (-3,1), (-3,-1)

// However, this is true only for a circle drawn about the origin (0,0),

// so to put the center of the circle to position (5,6) you must add 5

// to each row coordinate and 6 to each column coordinate:

//   (6,9), (6,3),  (4,9),  (4,3),   (8,7), (8,5),  (2,7),  (2,5)

 

void circle_pts (Point p, c)  // plot point p on a circle with origin c

{ plot(p.r + c.r, p.c + c.c);

  plot(p.r + c.r, -p.c + c.c);

  plot(-p.r + c.r, p.c + c.c);

  plot(-p.r + c.r, -p.c + c.c);

  plot(p.c + c.r, p.r + c.c);

  plot(p.c + c.r, -p.r + c.c);

  plot(-p.c + c.r, p.r + c.c);

  plot(-p.c + c.r, -p.r + c.c);

}

 

 

 

// This function "magically" determines points on a circle drawn

// about the origin (0,0) with a given radius.  It will find all the

// points in the first octant (north-northeast). For each point found,

// use the circle_pts function to draw the similar point in each octant.

 

void draw_circle (Point origin, int radius)

{ Point p(radius, 0);   // Create a point with r=radius and c=0

  int decision = 1 - radius;

  circle_pts(p, origin); // Draw the due North point first

  while (p.r > p.c)     // draw points while p is in the first octant

  { if (decision < 0)

    { decision += 2 * p.c + 3;  // magically works, don't ask me why.

      ++p.c;

    } else {

      decision += 2 * (p.c - p.r) + 5;

      ++p.c;  --p.r;

    }

    circle_pts(p, origin);

  }

}