Lab 8: Subroutines and APIs, with Mosaic

In today's lab, you will write a class containing certain subroutines.
There will be no main routine in that class; the subroutines are meant
for use in other classes. The class that you write will, in turn,
use *Mosaic.java*, which was discussed in class and which is
covered in Section 4.6.
(Actually, you will be using a slightly improved version. To see the
JavaDoc for the improved version, click here.)

In addition to subroutines and APIs, the lab gives you some experience with
working with a two-dimensional grid. You have already used one-dimensional
sequences in the form of strings. The individual characters in a string, *s*, are numbered,
and the i-th character can be accessed as *s.charAt*(*i*). Similarly,
the rectangles in a Mosaic are arranged in numbered rows and columns, and you need
to use two numbers to pick out an individual rectangle. We have not yet covered arrays, but
the idea of numbered positions is the essential concept behind arrays, and you are
getting some experience with that basic concept.

**This lab is due at the beginning of lab next Thursday. You should copy your
work into your homework folder by that time.**

*The due date for Project 2 has been postponed for one week, until Friday, October 28.*

**To begin the lab**, create a new project named *lab8*. Open the
directory */classes/cs120/lab8-files*, and copy the three files from
that project into your *lab8* src folder.
(The files are *Mosaic.java*,
*MosaicCanvas.java*, and
*ShapeTest.java*.)

There will be some errors in the
project, since many of the subroutines used by *ShapeTest.java* don't
exist yet. Your first job is to write those subroutines. Once the
subroutines are correctly implemented, then running *ShapeTest.java*
will create a mosaic window containing this picture:

**First**, create a new Java class named *MosaicShape*. The name must be exact,
since that's the name that is used in *ShapeTest*. You have to create
the following subroutines in *MosaicShape*. All the subroutines are *void*,
and all the parameters are of type *int*.

-- This routine sets the red, green, and blue components of the color that will be used by subsequent drawing operations.`setColor(r,g,b)`-- This routine draws a rectangle in the Mosaic window, by coloring all the squares in the given rectangle (using the color values set by the`rect(x,y,w,h)`*setColor*routine). The upper left-hand corner of the rectangle is at row y, column x. The rectangle is w squares wide and h squares high; that is, it extends over w columns and h rows. The values provided for w and h must both be greater than zero for anything to be drawn.-- fills in a disk with radius r and with center at row y, column x, using the color values set by`disk(x,y,r)`*setColor*.-- draws a line segment from the point at row y1, column x1 to the point at row y2, column x2, using the color values set by`line(x1,y1,x2,y2)`*setColor*. If x1 equals x2 and y1 equals y2, then the single square at row y1, column x1 should be colored.

I strongly suggest that you start by defining four **empty** subroutines.
This will eliminate the errors from *ShapeTest.java* and allow you
to run that program. You can then work on the subroutines one at a time,
and test each one as you work on it, by running *ShapeTest*.

When "drawing" things in these subroutines, the only basic operation that
you have is setting the color of one square in the mosaic window,
using the subroutine `Mosaic.setColor(row,column,red,green,blue)`.
You have to implement the drawing subroutines by calling this subroutine
for every individual square whose color you want to set. Of course, you can
really only draw approximations of the geometric shapes.

*rect* is pretty easy. It would be difficult to draw a disk efficiently,
but it is easy to do it inefficiently: To implement *disk*(x,y,r), go through
**every** row and column in the mosaic and color the squares that
satisfy

(x−column)^{2}+(y−row)^{2} <= r^{2}

Note that *Mosaic.getRows*() returns the number of rows in the mosaic,
and *Mosaic.getCols*() returns the number of columns.
As for lines, they are rather difficult and require some mathematics. You can
implement *line*(x1,y1,x2,y2) using the following pseudocode algorithm:

if x1 == x2 and y1 == y2: color the square at row y1, column x1 else if Math.abs( x1 - x2 ) > Math.abs( y1 - y2 ): slope = (double)(y2 - y1) / (x2 - x1) Let a be the smaller of x1,x2 Let b be the larger of x1,x2 for x from a to b: y = slope * (x - x1) + y1, rounded to the nearest integer color the square at row y, column x else: slope = (double)(x2 - x1) / (y2 - y1) Let a be the smaller of y1,y2 Let b be the larger of y1,y2 for y from a to b: x = slope * (y - y1) + x1, rounded to the nearest integer color the square at row y, column x

**Don't forget to provide JavaDoc-style comments, suitable for
documenting a reusable API!**

Once you have *ShapeDraw* working, your second exercise is to write a
program that uses it and *Mosaic*. For this program, you will need *TextIO*,
so you should add *TextIO.java* to your project.

The program that you will write will let the user type in "commands", which will be executed in the Mosaic window. The idea is that they user can draw shapes in a mosaic window by typing in commands (a strange interface for a drawing program!).

The program should simply run in a *while*(*true*)
loop. In the loop, you will read and execute one command. Each command will
start with a word, which you can read using *TextIO.getWord*(). After the
word there can be some integers that are used by the command. Some possible input lines
are:

open 40 40 10 rect 10 20 50 15 exit

The number of integers will depend on the command.
You should read the command and its parameters, if it needs them. You should then
carry out the command by calling an appropriate subroutine in either *Mosaic*
or *MosaicShape* (except for the *exit* command). Here is the complete
list of commands, with letters representing the integer parameters:

-- open a Mosaic window with r rows, c columns, and squares of size s-by-s.`open r c s`-- exit from the program`exit`-- close the mosaic window, but do not exit from the program`close`-- fill the entire mosaic with the color r,g,b`fill r g b`-- set the drawing color for shapes to r,g,b`color r g b`-- draw the line from (a,b) to (c,d)`line a b c d`-- draw the rect with corner (a,b), width w and height h`rect a b w h`-- draw the circle with center (a,b) and radius r`disk a b r`-- save the picture to a file (by calling Mosaic.saveImageToUserSelectedFile())`save`