// Screen.h - Interface for the Screen class. Since class Point // and class Screen are inter-dependent, and will be used together, // it makes sense to provide a single interface (dot-h) file. // // Written by (c) Wayne Pollock, 2000. All Rights Reserved. #ifndef SCREEN_H #define SCREEN_H #include //using namespace std; // not needed since I used std:: qualified names. // A simple point class. Although not necessary, this Point class // is implemented as a "Concrete Data Type" for illustration purposes. // Two useful overloaded operators are provided: equality testing ("==") // and addition. Although these short functions could be defined inline, // they are implemented elsewhere, again just for illustration. struct Point { int row; int col; Point () { row = 0; col = 0; } Point ( int r, int c ) { row = r; col = c; } Point ( const Point& p ) { row = p.row; col = p.col; } Point& operator= ( const Point& p ) { row = p.row; col = p.col; return *this; } ~Point () {} int operator== ( const Point& p ) const; Point operator+ ( const Point& ) const; }; // A Screen is a two dimensional grid of chars. The Screen keeps track of the // current char to plot with ("ink"), whose value can be examined and changed // with get_ink() and set_ink(). Additionally, when a point is plotted on the // Screen (via "plot()"), an optional argument can be supplied to override the // ink char used for that point only; zero means to use Screen::ink. // // Note that an attempt to plot points which aren't on the screen is not // an error; such points are ignored (note that "current_pt" is not updated.) // // A Screen can return its size via "size()"; the value returned is a // Point whose row member = the maximum row, and likewise for the column. // // A Screen also maintains the coordinates of the last Point ploted. This // Point is returned via "cur_pt()". (This is useful for extending lines // from the end of the previous line and for drawing concentric circles.) // The current point can be set with via "move_to()". // // Lastly, a Screen can be displayed to some output stream via "display()", // and a Screen can be erased (cleared, blanked) via "clear()". class Screen { public: // Default values for Screens: enum { NUM_ROWS = 20, NUM_COLS = 72, INK_DEFAULT = '*' }; Screen (); Screen ( const Screen& ); Screen& operator= ( const Screen& ); ~Screen () {} void clear ( char erase_char = ' ' ); void display ( std::ostream& = std::cout ) const; void draw_circle ( const Point& center, int radius, char ink = 0 ); void draw_line ( const Point& start_pt, const Point& end_pt, char ink = 0 ); char get_ink () const { return ink; } Point cur_pt () const { return current_pt; } void move_to ( const Point& ); // does noting if the Point is off-screen. void plot ( const Point&, char ink = 0 ); void set_ink ( char new_ink ) { ink = new_ink; } Point size () const; private: char ink; // The character to draw with. char rep[NUM_ROWS][NUM_COLS]; Point current_pt; // The last plotted point. void circle_points ( const Point&, const Point&, char temp_ink = 0 ); }; #endif
// main.cpp - main for sketch program. // Written by (c) Wayne Pollock, 2000. All Rights Reserved. #include #include // Older compilers require or . #include #include #include "screen.h" using namespace std; void parse_circle_cmd ( istringstream& cmd ); void parse_line_cmd ( istringstream& cmd ); void display_help (); void pause (); // Wait for user to hit Enter. Screen scrn; // This project uses only one screen object. int main () { char buf[256], cmd[256]; scrn.clear( '.' ); // start with empty screen. for ( ;; ) { try { scrn.display(); cerr << "\n\tEnter a command ('help' for brief help): " << flush; if ( !cin.getline( buf, sizeof (buf) ) ) break; istringstream ibuf( buf ); if ( !(ibuf >> cmd) ) continue; //A blank line is skipped. for ( unsigned int i=0; i < strlen(cmd); ++i ) // Capitalize command cmd[i] = (char) toupper( cmd[i] ); if ( strcoll( cmd, "CLEAR" ) == 0 ) { scrn.clear( '.' ); } else if ( strcoll( cmd, "EXIT" ) == 0 ) { return 0; } else if ( strcoll( cmd, "HELP" ) == 0 || strcoll( cmd, "?" ) == 0 ) { display_help(); } else if ( strcoll( cmd, "LINE" ) == 0 ) { parse_line_cmd( ibuf ); } else if ( strcoll( cmd, "CIRCLE" ) == 0 ) { parse_circle_cmd( ibuf ); } else { char err[256] = "Unrecognized command: "; strcat( err, cmd ); throw err; } } catch ( char* msg ) { cerr << "*** Error: " << msg << "!\a" << endl; pause(); } } // end for return 0; // If we get to here, an EOF was encountered! } // This code allows either two or four values: void parse_line_cmd ( istringstream& cmd ) { int start_row, start_col, end_row, end_col; Point start_pt, end_pt; char junk[256]; if ( !(cmd >> start_row) ) { throw "Bad first argument to Line"; } else if ( !(cmd >> start_col) ) { throw "Bad second argument to Line"; } else if ( !(cmd >> end_row) ) { // Assume a relative line! end_pt = scrn.cur_pt() + Point( start_row, start_col ); start_pt = scrn.cur_pt(); } else if ( !(cmd >> end_col) ) { throw "Bad fourth argument to Line"; } else if ( cmd >> junk ) { throw "Extra arguments to Line"; } else { start_pt = Point( start_row, start_col ); end_pt = Point( end_row, end_col ); } scrn.draw_line( start_pt, end_pt ); return; } // This code is tricky, since you can supply radius only, or row, col, radius: void parse_circle_cmd ( istringstream& cmd ) { int arg1, arg2, arg3, radius; char junk[256]; Point center; if ( !(cmd >> arg1) ) { throw "Bad first argument to Circle"; } else if ( !(cmd >> arg2) ) { if ( cmd >> junk ) throw "Bad second argument to Circle"; center = scrn.cur_pt(); // Else assume a relative circle. radius = arg1; } else if ( !(cmd >> arg3) ) { throw "Bad third argument to Circle"; } else if ( cmd >> junk ) { throw "Extra arguments to Circle"; } else { center = Point( arg1, arg2 ); radius = arg3; } if ( radius <= 0 ) throw "The circle's radius must be greater than zero"; scrn.draw_circle( center, radius ); return; } void display_help () { cerr << "\n\n\n\n\n\nSummary of Legal Commands:\n" << endl; cerr << "\tClear - erase the screen.\n" << endl; cerr << "\tCircle \n" << "\tCircle - draws a circle centered on " "the \"current point\".\n" << endl; cerr << "\tExit - quit the program.\n" << endl; cerr << "\tHelp (or \"?\") - display this message.\n" << endl; cerr << "\tLine \n" << "\tLine |
- draws a line from " "the \"current point\" to here.\n" << endl; cerr << "\n\n\n\n" << endl; pause(); } void pause () { char line[256]; cerr << "\nHit Enter to continue..." << flush; if ( !cin.getline( line, sizeof( line ) ) ) cin.clear(); // reset the EOF bit. return; }
Download Screen.cpp source file
// screen.cpp - implementation for Screen and Point classes. // Written by (c) Wayne Pollock, 2000. All Rights Reserved. #include #include #include // For older compilers use: #include "screen.h" using namespace std; //========================================================================= // Point Class implementation: //========================================================================= Point Point::operator+ ( const Point& p ) const { Point t( row, col ); t.row += p.row; t.col += p.col; return t; } int Point::operator== ( const Point& p ) const { return ( p.row == row && p.col == col ); } //========================================================================= // Screen class implementation: //========================================================================= // In this implementation, the grid of characters is represented as a // two dimentional array. // Any value can be used to draw (or erase) the screen, even ' ' (blank). // You can draw with ' ' to selectively erase parts of the image. // Note the origin is in the upper left-hand corner. Screen::Screen () { ink = INK_DEFAULT; current_pt.row = 0; current_pt.col = 0; } Screen::Screen ( const Screen& s ) { ink = s.ink; current_pt = s.current_pt; for ( int r=0; r = 0 && p.col >= 0 ) { if ( ! new_ink ) new_ink = ink; rep[p.row][p.col] = new_ink; current_pt.row = p.row; // Update the current point. current_pt.col = p.col; } return; } void Screen::move_to ( const Point& p ) // never move the point off-screen! { if ( p.row < NUM_ROWS && p.col < NUM_COLS && p.row >= 0 && p.col >= 0 ) current_pt = p; return; } void Screen::clear ( char erase_char ) // erase_char has a default value. { for ( int r=0; r abs( len_c ) ) len = abs( len_r ); double r_inc = len_r / double( len ); double c_inc = len_c / double( len ); double r = start_pt.row + 0.5; double c = start_pt.col + 0.5; for ( int i=0; i<=len; ++i ) { plot( Point( int( r ), int( c ) ), ink ); r += r_inc; c += c_inc; } return; } void Screen::draw_circle ( const Point& center, int radius, char ink ) { int r = radius; int c = 0; int decision = 1 - r; circle_points( Point( r, c ), center, ink ); while ( r > c ) { if ( decision < 0 ) { decision += 2 * c + 3; ++c; } else { decision += 2 * ( c - r ) + 5; ++c; --r; } circle_points( Point( r, c ), center, ink ); } move_to( center ); // Reset the current point to the center. return; } void Screen::circle_points ( const Point& p, const Point& c, char ink ) { plot( Point( p.row+c.row, p.col+c.col ), ink ); plot( Point( p.row+c.row, -p.col+c.col ), ink ); plot( Point( -p.row+c.row, p.col+c.col ), ink ); plot( Point( -p.row+c.row, -p.col+c.col ), ink ); plot( Point( p.col+c.row, p.row+c.col ), ink ); plot( Point( p.col+c.row, -p.row+c.col ), ink ); plot( Point( -p.col+c.row, p.row+c.col ), ink ); plot( Point( -p.col+c.row, -p.row+c.col ), ink ); return; }