The level 1 pictures are the initial state of our program, the first fibonacci square (with its circle arc in the first quadrant) and an H shape displayed.
The level 2 fibonacci spiral is created by adding the 2nd fibonacci square (with a circle arc in the 2nd quadrant) to the left of the 1st square, the level 3 by adding the 3rd fibonacci square (with a circle arc in the 3rd quadrant) below the first two squares. In general to create level n+1 from level n, just add the next n+1 fibonacci square. If the fibonacci square n has its circle arc in quadrant q, the fibonacci square n+1 has its circle arc in quadrant q + 1 (of course if q = 4, the next quadrant should be 1). Another issue is to add the next square at the correct location. Checking the quadrant of the last added square should tell you the location of the next square to add. For instance, square 1 has its circle arc in quadrant 1. The next quadrant is 2, which tells you that square 2 should go to the left of square 1.
To create the level 2 picture for the H, tile the H with 7 squares a third of the size of the original H and replace each square with an H as shown below.
To create level 3, just repeat the process with each one of the 7 H's drawn in level 2. Thus, level 3 has 49 H's.
When the program starts, the shapes are displayed in their initial state (level 1.) Display at least one fibonacci square and one H. Make sure that they don't overlap. Apart from these requirements, you can pick whatever size, color, location you want (Of course, it is better to pick a size so that it is easy to see the subsequent levels.) For each mouse click on a shape, the level will increment or decrement by 1 and the display is updated. There should be a reset button as well: when the user clicks on the reset button, the display goes back to the original state. Finally, the current level number should also be displayed and updated as the user works with the program (see the use of the TextViewer below).
There will be a limit on the number of levels the user can display. The program will stop adding to the spiral if it goes off screen or if overlaps with a neighboring shape (that is find the maximum fibonacci number allowed by the size of your frame and stop adding to the spiral when you reach that number.) The program will stop dividing the H shape if the sizes of the new H's are too small (e.g. < 25 pixels). A dialog box should pop up telling the user that they have reached the maximum level.
A dialog box should also pop up if the user wants to decrease the level below 1.
To model the fibonacci spiral, we can think of every fibonacci square n as being the child of the square n-1 that precedes it. For instance, at level 3, square 1 has one child = square 2. Square 2 has one child = square 3. And square 3 doesn't have any child.
For the H shape, a division can be thought of creating a covering of 7 smaller H's for every H making up the shape. That is we can think of an HShape has having 7 children. Even though the construction of the fibonacci spiral and the H are different, we can use the same approach for both and write some of the code in their common AbstractShape base class.
In the AbstractShape class, add an array of Shape objects to store the Shape objects that are the child shapes. Since the array will be of size 1 for a fibonacci square and of size 7 for an H shape, it can't be initialized in the constructor of AbstractShape. Make the visibility of the array protected and initialize the array in the constructors of the derived classes (FibonacciSquare and HShape). The elements of the children array are null for an initial fractal. When level 2 is created, the array is filled with actual shapes. For level 3, it is the arrays of the shapes that are added at level 2 that are filled, etc.
In the AbstractShape class, write a method to add a level (e.g. addLevel()) to a shape. It will do so by initializing the elements of the array of children for the last current level. This method will be called by the model when instructed by the controller to add a new level. Since the model has only a reference to the top level shapes, the method will iterate to get to the last level of the shape that was selected by the mouse click. Do so by using recursion (don't use any loop, except to loop over the elements of the array of children in a current level.) The base case of the method will be attained when the array of children is empty. Fill the array of children by calling a method (e.g. createChildren()) declared in the interface Shape and implemented in FibonacciSquare and HShape. Dynamic binding will automatically select the correct implementation! Of course, the array should be filled only if the spiral doesn't get too big, or if the H's don't get too small. Return a boolean to the model to tell it if a new level could be added. The boolean value can be relayed to the controller to tell it if the operation was successful. If a new level could not be added, then the controller displays a message box to the user explaining why (e.g. "size limit has been reached.")
In the AbstractShape class, write a method to remove a level (e.g. removeLevel()) from a shape. It will do so by setting to null the elements of the array of children for the last current level. This method will be called by the model when instructed by the controller to remove a level. Contrary to the addLevel method, removeLevel won't iterate to the last level of the selected shape. It will iterate to the level preceding the last level. This is because to remove the last level, the method needs to set to null the elements of the array of children that refer to that last level. As for addLevel, iterate by using recursion (that is don't use any loop, except to loop over the elements of the array of children in a current level.) If the shape that is displayed is at level 1, a level can't be removed. In that case, return false to the model. In all other cases, return true to the model. The boolean value will be passed on to the controller so that it can display a message box if a level could not be removed.
In AbstractShape, if you haven't done so in homework 3, provide a toString method for a shape. It should give the type of the shape (FibonacciSquare or HShape available by calling getClass()), the coordinates of the shape, its color and its current level.
In FibonacciSquare and HShape, modify the draw method. Recursion will come very handy when rewriting this method. Note that all levels are drawn for the fibonacci spiral, and that only the last level is drawn for an HShape.
You don't need to provide any deep copy method for a shape. If you have programmed a deep copy method for homework 2, you can remove the method.
Add any other methods that you think are needed for your implementation.
Changes to the Model
The model needs only to keep track of the shapes initially created since the shapes that are added when increasing the levels are stored within the initial shapes. Just add methods that allow the model to add or to remove a level to a shape.
There is also no need to return a deep copy of the list of shapes when sending a message to a view requiring the list of the shapes. In other words, you may just return the reference to the list of the shapes stored by the model in the method that returns the list of the shapes to a view.
Turn in your report as a pdf file along with your java files on the turn-in page.
Good Luck and start early!