C++ Intro

Assignment 4: drawing plane and coordinate system


Description

In this assignment you will write a program that uses 2-dimensional coordinate system and a drawing plane to allow users to create drawing primitives. Program functionality will be based on a 2-dimensional array of characters and a set of actions to manipulate its contents.

Part 1. Getting started

  1. Consider the following program, drawing_plane.cpp (download it here):
    
    #include <iostream>
    #include <cmath>  // for std::abs
    
    const int PLANE_WIDTH = 11;
    const int PLANE_HEIGHT = 10;
    
    void point( int x1, int y1, char plane[PLANE_HEIGHT][PLANE_WIDTH] );
    void tessellate( int x1, int y1, int x2, int y2, char plane[PLANE_HEIGHT][PLANE_WIDTH] );
    void display( char plane[PLANE_HEIGHT][PLANE_WIDTH] );
    
    void main()
    {
        static char plane[PLANE_HEIGHT][PLANE_WIDTH] = {
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' },
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' },
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' },
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' },
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' },
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' },
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' },
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' },
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' },
            { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\n' }
        };
    
        int x1;
        int y1;
        int x2;
        int y2;
    
        for(;;) {
            std::cout << "segment points: ";   // prompt for input
            std::cin >> x1 >> y1 >> x2 >> y2;  // get segment coordinates
            point( x1, y1, plane );            // draw first point
            point( x2, y2, plane );            // draw second point
            tessellate( x1, y1, x2, y2, plane ); // connect points
            display( plane );                  // display results
        }
    }
    
    // Mark point on the plane
    void point( int xx, int yy, char plane[PLANE_HEIGHT][PLANE_WIDTH] )
    {
        plane[yy][xx] = 'X';
    }
    
    // Connect two points
    void tessellate( int x1, int y1, int x2, int y2, char plane[PLANE_HEIGHT][PLANE_WIDTH] )
    {
        if ( std::abs( x1 - x2 ) < 2 && std::abs( y1 - y2 ) < 2 )
            // Nothing else left to do, two points are next to each other:
            return;
    
        // find center
        int cx = ( x1 + x2 )/2;
        int cy = ( y1 + y2 )/2;
    
        // mark center
        plane[cy][cx] = '*';
    
        // recurse and repeat
        tessellate( x1, y1, cx, cy, plane );
        tessellate( x2, y2, cx, cy, plane );
    }
    
    // Print content of the plane array
    void display( char plane[PLANE_HEIGHT][PLANE_WIDTH] )
    {
        for ( int yy = 0; yy < PLANE_HEIGHT; ++yy )
            for ( int xx = 0; xx < PLANE_WIDTH; ++xx )
                std::cout << plane[yy][xx];
    }
    
    
  2. The sample program creates a 2-dimensional array of characters named plane[ ]. The array gets initialized by spaces and new line characters. In the main loop, the user enters four integers, representing coordinates of the segment to be drawn on the plane. The two endpoints are drawn by calling function point( ). The endpoints are connected by a call to tessellate( ) function. The display( ) call prints the current drawing on the screen. For example, after entering 9 0 6 4 and 2 2 7 8, the two segments will appear as
             X
            *
      X    *
       *  *
       *  X
        *
         *
          *
           X
           
    
  3. Implementation of the sample program is rather straightforward. One exception is tessellate( ) function, which calls itself recursively. In each call the function calculates a mid-point of the given segment and marks it on the drawing plane with an asterisk '*'. Since mid-point divides the segment into two half-segments, the function calls itself two more times, once for each half-segment. In this process, the half-segments become smaller and smaller. Eventually, when the end-points are found right next to each other, the recursion stops, and tessellate( ) returns. The result of the tessellation is a mosaic of asterisk characters connecting the endpoints of the segment.

Part 2. Making the changes

  1. Your assignment is to modify the given sample to act as a command-driven drawing application.

  2. The program should support the following commands:
            quit
            segment x1 y1 x2 y2
            point x1 y1
            clear
            fill C
            
    
    where segment command draws a new segment, point draws a single point, clear fills the entire plane with blanks, effectively clearing the previous drawing, and fill fills all existing blanks with a character C, specified by the user. Please note that fill should not interfere with existing drawing primitives, thus altering only the background.

  3. Add a set of unique global integer constants to represent each of the above commands internally.

  4. Create a new function,
            void get_user_input( int params[] );
            
    
    This function should input a command text from the user, for example,
            std::string command;
            std::getline( std::cin, command );
            // or simply
            std::cin >> command;
            
    
    Using a series of else-if constructs, populate the initial params[ 0 ] element with the code of the command entered by the user:
            if ( command == "quit" ) {
                params[0] = name_of_your_constant_here;
                return;
            } else if ( command == "segment" ) {
                // ...
            }
            
    
    Next, according to each respectful command, request from the user and populate the list of parameters. You should validate each coordinate entered by the user against the boundaries of the plane[ ] array. (Hint: think what might happen if one of the coordinates in the sample program is out of bounds?)

  5. Create another new function,
            void dispatch_command( int params[] );
            
    
    to execute the action corresponding to the drawing command.

  6. Since this function will be responsible for all low-level manipulation of the drawing, the plane[ ] array should be moved here from the main( ) function. Because plane[ ] array is declared static , it will keep it's state unchanged between dispatch_command( ) function calls.

  7. The main( ) function should check if the entered command was "quit", to allow users to exit the application. Otherwise, it should execute the all-familiar endless loop, allowing the user to execute multiple drawing commands continuously.

  8. Think about ways to improve the application. One obvious thing to try is to enlarge the drawing space. You may also add new commands of your own choice to enhance the program and get extra points for this assignment.

Part 3. Another sample

The following program, drawing_plane_sample2.cpp (download it here) illustrates basic structure of functions get_user_input( ), and dispatch_command( ). In summary, it includes the following features, as required by this assignment:

  1. New constants added: command_quit, command_fill, command_clear .
  2. New functions added: get_user_input( ) and dispatch_command( ) .
  3. Array named cmd[] added to hold command code and command parameters.
  4. Function main( ) is modified to invoke new functions.
  5. The two-dimensional plane[] array has moved to the dispatch_command( ) function.
  6. Small help facility is added to give the user brief description of command formats.

Please note that this new sample IS NOT a replacement for the first sample, drawing_plane.cpp. The second sample only illustrates user input implementation and the use of the cmd[] array, but does not implement segment drawing. You need to study and combine both samples to do your work.

Part 4. Step-by-step instructions for implementing the changes

In order to implement the required changes, you may try follow these steps:

  1. Download drawing_plane_sample2.cpp and make sure it compiles fine on your system. I recommend that you use this program as a starting point to do this homework.

  2. Download drawing_plane.cpp and open it in a separate editor window. Locate definitions of the following functions, then copy these functions and paste them into your homework program:
    
        // Mark point on the plane
        void point( int xx, int yy, char plane[PLANE_HEIGHT][PLANE_WIDTH] )
        {
            // ...
        }
    
        // Connect two points
        void tessellate( int x1, int y1, int x2, int y2, char plane[PLANE_HEIGHT][PLANE_WIDTH] )
        {
            // ...
        }
    
    
  3. Compile your program again, it should compile without a problem.

  4. Locate the following constants in your code:
    
    const int command_quit = 100;
    const int command_fill = 200;
    const int command_clear = 300;
    
    
    Add two more constants to your program:
    
        const int command_segment = 400; 
        const int command_point = 500; 
    
    
  5. Inside your get_user_input( ) function, type additional handlers for the user commands clear, segment, and point:
    
        } else if ( command == "clear" ) {
            params[0] = command_clear;
    
        } else if (command == "segment") {
            params[0] = command_segment;
            // get segment coordinates:
            std::cin >> params[1] >> params[2] >> params[3] >> params[4];
    
        } else if (command == "point") {
            params[0] = command_point;
            // get point coordinates:
            std::cin >> params[1] >> params[2];
        }
    
    
  6. Compile your program again, it should compile without a problem.

  7. Inside your dispatch_command( ) function, type additional handlers for the user commands clear, segment, and point:
    
        } else if ( params[0] == command_clear ) {
            for ( int yy = 0; yy < PLANE_HEIGHT; ++yy )
                for ( int xx = 0; xx < PLANE_WIDTH; ++xx )
                    if ( plane[yy][xx] != '\n' )
                        plane[yy][xx] = ' ';
    
        } else if ( params[0] == command_segment ) {  
            point( params[1], params[2], plane );            // draw first point
            point( params[3], params[4], plane );            // draw second point
            tessellate( params[1], params[2], params[3], params[4], plane ); // connect points
    
        } else if ( params[0] == command_point ){
            point( params[1], params[2], plane );            // draw first point
        }
    
    
  8. Now compile your program and test some drawing commands. Try, for example,
    Enter your command> segment 0 0 9 9
    X
     *
      *
       *
        *
         *
          *
           *
            *
             X
    
    Enter your command> point 6 8
    X
     *
      *
       *
        *
         *
          *
           *
          X *
             X
    
    Enter your command> point 7 0
    X      X
     *
      *
       *
        *
         *
          *
           *
          X *
             X
    
    Enter your command> fill -
    X------X--
    -*--------
    --*-------
    ---*------
    ----*-----
    -----*----
    ------*---
    -------*--
    ------X-*-
    ---------X
    
    Enter your command> clear