Question

In: Computer Science

Purpose For this programming project, you will create an application that draws fractal-like shapes using recursion....

Purpose


For this programming project, you will create an application that draws fractal-like shapes using recursion. The class that creates the graphics window for the display of the shapes is given to you (see below). What you have to do is create a set of classes for the three shapes that are displayed in the graphics window. Two of the shapes must be a Sierpinski triangle and an H-shape. The third shape is your choice, though it must be a fractal-like shape. There is also the possibility of earning a few extra-credit points (up to 3 points) by allowing some deformation of the shapes while moving a slider on the graphics window.


FractalDisplay class (code: http://flepeint.ccfaculty.org/java143/hw3/FractalDisplay.java)


The FractalDisplay class is given and requires very minimal coding on your part. Instantiating the FractalDisplay class displays a graphics window, which features 3 radio buttons for the selection of the shapes, two buttons to add or remove a level to the shapes, and a slider that when moved should deform the shapes in an interesting manner. The slider feature is not required and should only be attempted for extra-credit once the rest of the assignment is completed.


The only code you will write in FractalDisplay is to call the constructors of the three concrete shape classes of this project, namely the SierpinskiTriangle, HShape, and MyShape classes. Look for the comment //TODO. Only 3 lines of code are needed, one for each of the calls of the constructors of the three concrete shape classes.


Drawing of the shapes


For this programming project, three shapes are required. Two of them must be a Sierpinski triangle and an H shape. The third one is your choice, though it must be a fractal-like shape. You can get some ideas by consulting this page.


The Sierpinski triangle starts with one triangle. We call this level 1 of the triangle. At level 2, 3 triangles are added inside of the first triangle. At level 3, 3 more triangles are added inside of the three level 2 triangles. Mathematically, the process goes on forever. For our display, this is of course not possible since we are limited by the size of single pixel on the computer screen. We will limit the level to a maximum value of 10 for the Sierpinski triangle.


Level 1: 1 triangleLevel 2: 1 + 1 * 3 = 4 trianglesLevel 3: 1 + 1 * 3 + 3 * 3 = 13 triangles

The H-shape follows the same pattern as the Sierpinski triangle.


Initially, at level 1, there is one H. At level 2, 7 H's are drawn within the seven squares making up the original H. And at level 3, 7 more H's are added in the 7 seven H's of level 2. As for the Sierpinski triangle, we need to limit the level to a maximum value, which will be 5 for the H shape.


Level 1: 1 HLevel 2: the shape has 1 + 1 * 7 = 8 H's (but only the last level is drawn since the level 1 H would hide the smaller H shapes)Level 3: the shape has 1 + 1 * 7 + 7 * 7 = 57 H's (though only the level 2 H's are displayed)

Organization of the shape classes


Since the 3 shapes that are displayed have many features in common (e.g. all of them may add a level or remove a level), we want to use inheritance to avoid code repetition. To do so, we start by listing all of the common methods in a Shape interface. As an aside, notice that the code of FractalDisplay knows only about the Shape type except for the actual constructor calls of the concrete shape classes. This is of course the advantage of using inheritance. It creates a low coupling between the FractalDisplay class and the concrete shape classes, that is the code of FractalDisplay doesn't rely heavily on the implementation of the Shape interface by the concrete shape classes.


The Shape interface will contain the following methods


void draw(Graphics g)Draws this shapeboolean addLevel()Adds a level to this shape. Returns true if the operation was successful or false if the maximum level has been reached.boolean removeLevel()Removes a level from this shape. Returns true if the operation was successful or false if the shape was at level 1.int countShapes()Returns the total number of shapes of this shape (e.g. 57 for the H shape at level 2).void update(int value)Modifies this shape in an interesting way given a value in the range 0-100. This method is only required for the extra-credit part.

When thinking about the implementation of the Shape interface by the concrete shape classes, you will notice many similarities between all of the implementations. For that reason, it is a good idea to create an abstract class AbstractShape that implements Shape and contains the code that is common to all three concrete shape classes. By inheriting AbstractShape, the concrete shape classes get the methods implemented in AbstractShape and just need to add their own specific code (e.g. the implementation of the draw method). This is leading us to the following class hierarchy:


As just mentioned, AbstractShape will contain the fields and methods that can be used by all of the concrete shape classes. For instance, all shapes have a level, a maximum level value, a color, and may have children shapes (e.g. any Sierpinski triangle may have 3 inner triangles, and any H may have 7 inner H's). A possible design of AbstractShape would list fields to store that information. For instance:


public abstract class AbstractShape implements Shape {


protected int level;
protected int maxLevel;
protected AbstractShape[] children;
protected Color color;
// The fields may be initialized by the AbstractShape constructor with the values
// received from the super() calls in the constructors of the concrete shape classes.
// For instance, the SierpinskiTriangle constructor may call the AbstractShape constructor with
// the a max level value of 10 and a children array length of 3
// Alternatively the fields may be initialized in the concrete class constructors (they are visible by
// the concrete classes since they are declared protected)


What precisely goes in the AbstractShape class depends on your implementation design, though I strongly recommend that you follow the guidelines given in the next section. In any case, make sure that you avoid any code repetition among your implementations of the concrete classes. It is possible to have all of the methods of the Shape interface implemented by AbstractShape except for the draw method (and possibly the update method if you attempt the extra credit part).


Implementation details


The details outlined below use the HShape and SierpinskiTriangle classes as illustrations. However, they should be readily applicable to the fractal shape that you select as your third shape (coded in the MyShape class).


addLevel() method (must use recursion)


As mentioned in the previous section, it is possible to implement the addLevel method in the AbstractShape class. The only addition to a concrete class can just be a method to create the actual child shapes.


To model the Sierpinski triangle, we can think of the triangles at level n as being the children of the triangle at level n-1. For instance, for a Sierpinski triangle with three levels, the level 1 triangle has three children which are the three level 2 triangles. Each of the three level 2 triangle has also three children on level 3, for a total of nine triangles. And the nine triangles at level 3 have no children since they are on the last level.


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 Sierpinski triangle 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 AbstractShape objects to store the AbstractShape objects that are the child shapes. For example, the array will be of length 3 for a Sierpinski triangle and of length 7 for an H shape. The array may be initialized in the constructor of AbstractShape if the AbstractShape constructor takes the array length as a parameter, or directly in the constructor of the concrete classes if you make the visibility of the array protected. 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, implement the addLevel() method to add a level to a shape. It will do so by initializing the elements of the array of children for the last current level. In the FractalDisplay class, you can check that the method is called whenever the "Add level" button is clicked. Since the FractalDisplay class has only a reference to the top level shape, the method will iterate to get to the last level of the shape. 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 abstract in AbstractShape and implemented in the concrete shape classes. Dynamic binding will automatically select the correct implementation! Of course, the array should be filled only if the maximum level has not been reached. Return a boolean to tell it if a new level could be added. The boolean value is relayed to the FractalDisplay class to tell it if the operation was successful. If a new level could not be added, then the FractalDisplay displays a message box saying that no new level can be added.


removeLevel() method (must use recursion)


In the AbstractShape class, implement removeLevel() to remove a level from a shape. If a shape has n levels, the last level may be removed by setting to null the elements of the array of children at level n-1. This method is called by the DisplayFractal class whenever the button "Remove level" is clicked. 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, removeLevel returns false. The boolean value will be passed on to the display so that it can display a message box if a level could not be removed.


countShapes() method (must use recursion)


In the AbstractShape class, implement countShapes() to count the total number of shapes in a shape. If there is only one shape (level 1), the count is 1. For a shape with two levels, the count is 1 + number of shapes at level 2, that is 4 triangles for a Sierpinski triangle with two levels, or 8 H's for an H with two levels. For a shape with three levels, the counts are 13 for a Sierpinski triangle and 57 for an H.


As for addLevel and removeLevel, your implementation must use recursion except to loop over the children shapes in a current level.


The countShapes() method is called from the FractalDisplay class whenever the mouse is right clicked on a shape.


draw() method (must use recursion)


This is the method that must be implemented in each concrete class (SierpinskiTriangle, HShape and MyShape). The method takes a Graphics object that can draw almost anything. Check the documentation of the Graphics class in the java documentation pages. For example, the Sierpinski triangle may be drawn by invoking the drawPolygon method.


As for all of the other methods discussed in this section, use recursion to implement the method except to loop over the array of children.


Extra-credit (up to 3 points)


Implement the update() method that takes an integer in the 0-100 range and modifies the display of the current shape as a function of the value of the integer. The value is changed by moving a slider on the display window. Initially the value given by the slider is set at 50. As an illustration, here is an example with the Sierpinski triangle


Solutions

Expert Solution

Working code implemented in Java and appropriate comments provided for better understanding.

Here I am attaching code for all files:

AbstractShape.java:

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

public abstract class AbstractShape implements Shape {

   protected AbstractShape[] children; // the array of children shapes
   protected int level, width, height, drawStartX, drawStartY; // level, width and height of the graphics frame, origin starting at (0,0)
   protected final int maxLevel;        // max level determined by each shape class
   protected Color color;               // the color the shape will be drawn in
   protected double sliderVal = 1.0; // slider value that skews the shapes
   public static int count;           // the number of shapes in the display
   private static Random rand = new Random();

   /**
   * AbstractShape child constructor shared by the shape subclasses
   *
   * @param drawStartX
   * x-coordinate origin
   * @param drawStartY
   *            y-coordinate origin
   * @param width
   * width of the graphics space
   * @param height
   *            height of the graphics space
   * @param maxlevel
   * maximum level of recursion
   * @param level
   * current level of recursion
   *
   */
   protected AbstractShape(int drawStartX, int drawStartY, int width, int height, int maxLevel, int level) {
       this(maxLevel,level);
       this.drawStartX = drawStartX;
       this.drawStartY = drawStartY;
       this.width = width;
       this.height = height;
   }


   /**
   * AbstractShape constructor shared by the shape subclasses
   *
   * @param maxlevel
   * maximum level of recursion
   * @param level
   * current level of recursion
   * @param color
   * color of the shape
   *
   */
   protected AbstractShape(int maxLevel, int level) {
       this.maxLevel = maxLevel;
       this.level = level;
       this.color = new Color(rand.nextInt());
   }

   /**
   * Draws the current state of the recursive image
   *
   * @param g
   * the Graphics context on which to draw
   */
   @Override
   public void draw(Graphics g) {
       g.setColor(color);
       if (children == null) {
           drawBaseShape(g);
       } else {
           for (AbstractShape child : children) {
               child.draw(g);
           }
       }
   }
   /**
   * Draw the base shape
   */
   protected abstract void drawBaseShape(Graphics g);

   /**
   * Adds a level of recursive shapes
   *
   * @return boolean
   *            Whether or not a level was added
   */
   @Override
   public boolean addLevel() {
       if (level == maxLevel) {
           return false;
       } else if (children != null) {
           for (Shape child : children) {
               if (!child.addLevel()) {
                   return false;
               }
           }
       } else {
           createChildren();
       }
       count = countShapes();
       return true;
      
   }

   /**
   * Reverses the recursive drawing of the shape and removes level
   *
   * @return boolean
   *            Whether or not a level was removed
   */
   @Override
   public boolean removeLevel() {

       if (children == null) {
           return false;
       } else if (children[0].children == null) {
           children = null;
       } else {
           for (AbstractShape child : children) {
               child.removeLevel();
           }
       }
       count = countShapes();
       return true;

   }

   /**
   * Recursive algorithm to count the number of shapes
   *
   * @return numOfShapes
   *                The number of shapes below this shape and this shape
   */
   @Override
   public int countShapes() {
       if (children != null) {
           int numOfShapes = 0;
           for (AbstractShape child : children) {
               numOfShapes += child.countShapes();
           }
           return numOfShapes;
       } else {
           return 1;
       }
   }
  
   /**
   * Send shape count to FractalDisplay
   *
   * @return count
   *            The number of shapes
   */
   public static int getCount() {
       return count;
   }
  

   /**
   * Updates values for the slider
   *
   * @param value
   *            The new slider value
   */
   @Override
   public void update(int value) {
       sliderVal = value / 50.0;
       int depth = findDepth();
       children = null;
       createChildrenAtDepth(depth);
   }

   /**
   * @param depth
   *            how deep to make the tree
   */
   private void createChildrenAtDepth(int depth) {
       if (depth > 1) {
           createChildren();
           depth--;
           for (AbstractShape child : children) {
               child.createChildrenAtDepth(depth);
           }
       }
   }

   /**
   * @return int depth
   *                the depth of the tree
   */
   private int findDepth() {
       if (children == null) {
           return 1;
       } else {
           return 1 + children[0].findDepth();
       }
   }

   /**
   * Create a new set of children.
   */
   protected abstract void createChildren();

}

FractalDisplay.java

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
* Construct a window to display the fractal shapes. This class is almost
* complete. Add your own code only in the places marked with the comment TODO
*
*/

public class FractalDisplay extends JPanel implements MouseListener, ActionListener, ChangeListener {

   // Width of the inner panel
   public static final int WIDTH = 800;

   // Height of the inner panel
   public static final int HEIGHT = 800;

   // Possible shapes
   private int which;
   public static final int SIERPINSKI_TRIANGLE = 0;
   public static final int H_SHAPE = 1;
   public static final int MY_SHAPE = 2;

   private JFrame frame;

   // Other elements in the window
   // Radio buttons (with their titles)
   private String[] titles;
   private JRadioButton[] radioButtons;

   // The button to add/remove levels
   private JButton addLevel, removeLevel;

   // Slider to change the display (extra-credit feature)
   private JSlider slider;

   // Current shape
   private Shape shape;

   // Use a popup menu to display information
   // the total number of shapes in the current shape
   // -> triggered by a right click of the the mouse.
   private JPopupMenu popup;
   private JLabel popupLabel;
   private JLabel label;


   /**
   * Constructs a FractalDisplay to display fractal shapes
   */
   public FractalDisplay() {
       // Use a windows look and feel (if available)
       try {
           UIManager.LookAndFeelInfo[] lfinfo = UIManager.getInstalledLookAndFeels();
           UIManager.setLookAndFeel(lfinfo[4].getClassName());
       } catch (Exception e) {/* ignore any problem */
       }

       // Radio buttons
       titles = new String[] { "Sierpinski Triangle", "HShape", "My shape" };
       radioButtons = new JRadioButton[titles.length];
       // Only one radio button can be selected at a time
       ButtonGroup buttonGroup = new ButtonGroup();
       for (int i = 0; i < radioButtons.length; i++) {
           radioButtons[i] = new JRadioButton(titles[i]);
           buttonGroup.add(radioButtons[i]);
           radioButtons[i].addActionListener(this);
       }

       // Button to add or remove levels to the shape
       addLevel = new JButton("Add level");
       addLevel.addActionListener(this);
       removeLevel = new JButton("Remove level");
       removeLevel.addActionListener(this);

       // Slider to change the shape
       slider = new JSlider(0, 100, 50);
       slider.addChangeListener(this);

       // Place the components in the frame
       JPanel contentPane = new JPanel();
       contentPane.setLayout(new BorderLayout());
       // at the bottom (SOUTH)
       JPanel southPanel = new JPanel(new GridLayout(3, 1));
       JPanel southPanelFirstRow = new JPanel();
       for (int i = 0; i < radioButtons.length; i++)
           southPanelFirstRow.add(radioButtons[i]);
       southPanel.add(southPanelFirstRow);
       JPanel southPanelSecondRow = new JPanel();
       southPanelSecondRow.add(addLevel);
       southPanelSecondRow.add(removeLevel);
       southPanel.add(southPanelSecondRow);
       contentPane.add(southPanel, BorderLayout.SOUTH);
       JPanel southPanelThirdRow = new JPanel();
       southPanelThirdRow.add(slider);
       southPanel.add(southPanelThirdRow);

       setBackground(Color.WHITE);
       contentPane.add(this, BorderLayout.CENTER);
      
       label = new JLabel("Number of shapes: ");
       label.setFont(new Font("Courier", Font.BOLD, 32));
       JPanel northPanel = new JPanel();
       northPanel.setBackground(Color.WHITE);
       northPanel.add(label);
       contentPane.add(northPanel, BorderLayout.NORTH);

       // Get ready to listen to mouse clicks
       addMouseListener(this);

       // Put everything in a frame
       frame = new JFrame("Recursive graphics");
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.setContentPane(contentPane);
       // Show it
       frame.setSize(WIDTH, HEIGHT);
       frame.setVisible(true);
       // Resize it with the actual size
       Insets insets = frame.getInsets();
       int width = WIDTH + insets.left + insets.right;
       int height = HEIGHT + insets.top + insets.bottom + (int) (southPanel.getPreferredSize().getHeight()) + (int) (northPanel.getPreferredSize().getHeight());
       frame.setSize(width, height);
       frame.setResizable(false);
       frame.setVisible(true);

       // popup menu
       popup = new JPopupMenu();
       popupLabel = new JLabel("", SwingConstants.CENTER);
       popupLabel.setFont(new Font("Courier", Font.BOLD, 32));
       popup.add(popupLabel);
      
      

   }

   /**
   * Handles the button clicks
   *
   * @param e the ActionEvent generated by the click
   */
   public void actionPerformed(ActionEvent e) {
       if (e.getSource().getClass() == JRadioButton.class) {
           for (int i = 0; i < radioButtons.length; i++) {
               if (e.getSource() == radioButtons[i]) {
                   which = i;
                   // reset the slider to its default value
                   slider.setValue(50);
                   break;
               }
           }
           switch (which) {
           case SIERPINSKI_TRIANGLE:
               shape = new SierpinksiTriangle(WIDTH, HEIGHT);
               shape.update(slider.getValue());
               break;
           case H_SHAPE:
               shape = new HShape(WIDTH, HEIGHT);
               break;
           case MY_SHAPE:
               shape = new MyShape(WIDTH, HEIGHT);
               break;
           }
       } else if (e.getSource() == addLevel) {
           // Don't do anything if there is no display
           if (shape != null) {
               boolean success = shape.addLevel();
               label.setText("Number of Shapes = " + AbstractShape.getCount());
               if (!success) {
                   JOptionPane.showMessageDialog(this, "Can't add another level", "Message",
                           JOptionPane.WARNING_MESSAGE);
               }
           }
       } else if (e.getSource() == removeLevel) {
           // Don't do anything if there is no display
           if (shape != null) {
               boolean success = shape.removeLevel();
               label.setText("Number of Shapes = " + AbstractShape.getCount());
               if (!success) {
                   JOptionPane.showMessageDialog(this, "Can't remove another level", "Message",
                           JOptionPane.WARNING_MESSAGE);
               }
           }
       } else {
           // unknown source
           return;
       }

       // display the new drawing
       repaint();
   }

   /**
   * Paints the shape
   */
   public void paintComponent(Graphics gfx) {
       super.paintComponent(gfx);
       // If there is nothing to display, stop here
       if (shape != null) {
           // Use some graphics2D features (smooth edges)
           Graphics2D g = (Graphics2D) gfx;
           g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
           shape.draw(g);
       }
   }

   /**
   * Different platforms might have different ways to trigger a popup menu: check
   * all possibilities
   */
   public void mousePressed(MouseEvent e) {
       checkPopup(e);
   }

   public void mouseClicked(MouseEvent e) {
       checkPopup(e);
   }

   public void mouseReleased(MouseEvent e) {
       checkPopup(e);
   }

   /**
   * Displays a message box giving the total number shapes in the current shape
   */
   private void checkPopup(MouseEvent e) {
       // Do it only if we have a request for a pop up menu, aka right click...
       if (!e.isPopupTrigger()) {
           return;
       }

       // Display the information about the shape currently painted
       if (shape != null) {
           int count = shape.countShapes();
           popupLabel.setText("total number of shapes = " + count);
           popup.show(e.getComponent(), e.getX(), e.getY());
       }
   }

   @Override
   public void stateChanged(ChangeEvent e) {
       if (shape != null) {
           shape.update(slider.getValue());
           repaint();
       }
   }

   public void mouseExited(MouseEvent e) {
   }

   public void mouseEntered(MouseEvent e) {
   }

   /**
   * Starts the application
   */
   public static void main(String[] args) {
       new FractalDisplay();
   }
}
Shape.java:

import java.awt.Graphics;

public interface Shape {
   /**
   * Draws the current state of the recursive image
   *
   * @param g
   * the Graphics context on which to draw
   */
   void draw(Graphics g);
  
   /**
   * Adds a level of recursive shapes
   *
   * @return boolean
   *            Whether or not a level was added
   */
   public boolean addLevel();
  
   /**
   * Reverses the recursive drawing of the shape and removes level
   *
   * @return boolean
   *            Whether or not a level was removed
   */
   public boolean removeLevel();
  
   /**
   * Recursive algorithm to count the number of shapes
   *
   * @return numOfShapes
   *                The number of shapes below this shape and this shape
   */
   public int countShapes();
  
   /**
   * Updates values for the slider
   *
   * @param value
   *            The new slider value
   */
   public void update(int value);
}

HShape.java:

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

public class HShape extends AbstractShape {

   protected static final int maxLevel = 5;
  
  

   /**
   * Create a new HShape.
   * This constructor is used when creating the root HShape object.
   *
   * @param width
   *        The width of the display.
   * @param height
   *        The height of the display.
   */
   public HShape(int width, int height) {
       this(0,0,width,height,1);  
   }

   /**
   * Create a new HShape.
   * This constructor is used for creating children.
   *
   * @param drawStartX
   * x-coordinate origin
   * @param drawStartY
   *            y-coordinate origin
   * @param width
   * width of the graphics space
   * @param height
   *            height of the graphics space
   * @param level
   * The depth of this shape in relation to the root.
   */
   public HShape(int drawStartX, int drawStartY, int width, int height, int level) {
       super(drawStartX, drawStartY, width, height, maxLevel, level);
   }

   /**
   * Create a new set of children.
   */
   @Override
   protected void createChildren() {
       this.children = new AbstractShape[7];

       int newLevel = level + 1;
       int childWidth = (int) Math.round(width / 3.0);
       int childHeight = (int) Math.round(height / 3.0);
       int childNumber = 0;

       for (int row = 0; row < 3; row++) {
           for (int col = 0; col < 3; col++) {
               if (col == 1 && row != 1) {
                   continue;
               }
               // make child
               children[childNumber] = new HShape(childWidth * col + drawStartX, childHeight * row + drawStartY,
                       childWidth, childHeight, newLevel);
               childNumber++;
           }
       }
   }


   /**
   * Draw the base shape
   */
   protected void drawBaseShape(Graphics g) {
       g.fillRect(drawStartX, drawStartY, width / 3, height);
       g.fillRect(drawStartX + width / 3, drawStartY + height / 3, width / 3, height / 3);
       g.fillRect(drawStartX + width / 3 * 2, drawStartY, width / 3, height);

   }

}
MyShape.java:

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

public class MyShape extends AbstractShape {
   protected static final int maxLevel = 7;
  


   /**
   * Construct a new MyShape.
   * This constructor is for the initial root shape.
   *
   * @param width
   *        The width of the display.
   * @param height
   *        The height of the display.
   */

   protected MyShape(int width, int height) {
       this(0, 0, width, height, 1);
      
   }

   /**
   * Construct a new MyShape.
   * This constructor is used for creating children.
   *
   * @param drawStartX
   * x-coordinate origin
   * @param drawStartY
   *            y-coordinate origin
   * @param width
   * width of the graphics space
   * @param height
   *            height of the graphics space
   * @param level
   * The depth of this shape in relation to the root.
   *
   */
   protected MyShape(int drawStartX, int drawStartY, int width, int height, int level) {

       super(drawStartX, drawStartY, width, height, maxLevel, level);
   }

   /**
   * Create a new set of children.
   */
   @Override
   protected void createChildren() {
       this.children = new AbstractShape[8];
       // nearly identical to the HShape...
       int newLevel = level + 1;
       int childWidth = (int) Math.round(width / 3.0);
       int childHeight = (int) Math.round(height / 3.0);
       int childNumber = 0;

       for (int row = 0; row < 3; row++) {
           for (int col = 0; col < 3; col++) {
               if (col == 1 && row == 1) {
                   continue;
               }
               // make child
               children[childNumber] = new MyShape(childWidth * col + drawStartX, childHeight * row + drawStartY,
                       childWidth, childHeight, newLevel);
               childNumber++;
           }
       }

   }

   /**
   * Draw the base shape
   */
   @Override
   protected void drawBaseShape(Graphics g) {
       g.fillRect(drawStartX, drawStartY, width, height);

   }
}

SierpinksiTriangle.java:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import java.util.Random;

public class SierpinksiTriangle extends AbstractShape {
   protected static final int maxLevel = 10; // The max depth of the tree from the root.
   private int[] xPoints = new int[4]; // array of integers representing the x values of the triangles vertices.
   private int[] yPoints = new int[4]; // array of integers representing the y values of the triangles vertices.
  

   /**
   * Construct the initial SierpinksiTriangle shape.
   *
   * @param width
   *        The initial display width
   * @param height
   *        The initial display height
   */
   protected SierpinksiTriangle(int width, int height) {
       // Height - 1 to prevents the line from being drawn outside the box;
       // it seems the display box has a height of 800 but only displays [0,799]
       // I'm not concerned with loosing the last pixel of the right side, so width was not adjusted.
      
       this(
           new int[] { 0, width / 2, width, 0 },            // xPoints
           new int[] { height-1, 0, height-1, height-1 }, // yPoints
           1.0,                                           // slider value
           1                                               // starting level
           );
   }

   /**
   * Construct a new SierpinksiTriangle.
   *
   * This constructor is used for creating children.
   *
   * @param xPoints
   *        array of integers representing the x values of the triangles vertices.
   * @param yPoints
   *        array of integers representing the y values of the triangles vertices.
   * @param sliderVal
   *        The value of the slider
   * @param level
   *        The depth of this shape in relation to the root.
   *
   */
   protected SierpinksiTriangle(int[] xPoints, int[] yPoints,double sliderVal, int level) {
       super(maxLevel, level);
       this.xPoints = xPoints;
       this.yPoints = yPoints;
       this.sliderVal = sliderVal;
   }


   /**
   * Create a new set of children.
   */
   @Override
   protected void createChildren() {
       this.children = new AbstractShape[3];
       int newLevel = level + 1;

       int[] sharedX = new int[] {
               (int) ((xPoints[1] - xPoints[0]) / 2.0 * sliderVal) + xPoints[0],
               (int) ((xPoints[2] - xPoints[1]) / 2.0 * sliderVal) + xPoints[1],
               (int) (xPoints[2] + ((xPoints[0] - xPoints[2]) / 2.0 * sliderVal)) };

       int[] sharedY = new int[] {
               (int) (yPoints[0] - ((yPoints[0] - yPoints[1]) / 2.0 * sliderVal)),
               (int) (yPoints[1] + ((yPoints[2] - yPoints[1]) / 2.0 * sliderVal)),
               (int) (yPoints[2] + ((yPoints[0] - yPoints[2]) / 2.0 * sliderVal)) };

       children[0] = new SierpinksiTriangle(new int[] { xPoints[0], sharedX[0], sharedX[2], xPoints[3] },
                                           new int[] { yPoints[0], sharedY[0], sharedY[2], yPoints[3] },
                                           sliderVal, newLevel);

       children[1] = new SierpinksiTriangle(new int[] { sharedX[0], xPoints[1], sharedX[1], sharedX[0] },
                                           new int[] { sharedY[0], yPoints[1], sharedY[1], sharedY[0] },
                                           sliderVal, newLevel);

       children[2] = new SierpinksiTriangle(new int[] { sharedX[2], sharedX[1], xPoints[2], sharedX[2] },
                                           new int[] { sharedY[2], sharedY[1], yPoints[2], sharedY[2] },
                                           sliderVal, newLevel);


   }

   /**
   * Draw the base shape
   */
   @Override
   protected void drawBaseShape(Graphics g) {
       g.drawPolyline(xPoints, yPoints, 4);
   }

}

Sample Output Screenshots:


Related Solutions

Create a project plan on the game or application you are creating. Using java programming. The...
Create a project plan on the game or application you are creating. Using java programming. The project plan should include the following: A description of the game or application The IDE or game engine your plan to use to create the game or app and information on how you are going to develop the game or app If you choose to create a game, how are you going to approach the game design and game development process or if you...
In this programming assignment, you will write C code that performs recursion. For the purpose of...
In this programming assignment, you will write C code that performs recursion. For the purpose of this assignment, you will keep all functions in a single source file main.c. Your main job is to write a recursive function that generates and prints all possible password combinations using characters in an array. In your main() function you will first parse the command line arguments. You can assume that the arguments will always be provided in the correct format. Remember that the...
C# Programming language!!! Using visual studios if possible!! PrimeHealth Suite You will create an application that...
C# Programming language!!! Using visual studios if possible!! PrimeHealth Suite You will create an application that serves as a healthcare billing management system. This application is a multiform project (Chapter 9) with three buttons. The "All Accounts" button allows the user to see all the account information for each patient which is stored in an array of class type objects (Chapter 9, section 9.4).The "Charge Service" button calls the Debit method which charges the selected service to the patient's account...
Can you please solve this using recursion/ dynamic programming? Any programming language is fine. Wallace the...
Can you please solve this using recursion/ dynamic programming? Any programming language is fine. Wallace the Weightlifting Walrus is training for a contest where it will have to lift 1000 kg. Wallace has some weight plates lying around, possibly of different weights, and its goal is to add some of the plates to a bar so that it can train with a weight as close as possible to 1000 kg. In case there exist two such numbers which are equally...
The Programming Language is C++ Objective: The purpose of this project is to expose you to:...
The Programming Language is C++ Objective: The purpose of this project is to expose you to: One-dimensional parallel arrays, input/output, Manipulating summation, maintenance of array elements. In addition, defining an array type and passing arrays and array elements to functions. Problem Specification: Using the structured chart below, write a program to keep records and print statistical analysis for a class of students. There are three quizzes for each student during the term. Each student is identified by a four-digit student...
1. How is using authoring application to design a project different from using a programming language...
1. How is using authoring application to design a project different from using a programming language to build the same project? 2. What are some concerns about designing multimedia for the internet? 3. Why would you might want use lossy compression or lossless compression for an image? 4. How could you compare vectors to bitmaps?
Create a new Java project named Program 4 Three Dimensional Shapes. In this project, create a...
Create a new Java project named Program 4 Three Dimensional Shapes. In this project, create a package named threeDimensional and put all 3 of the classes discussed below in this package Include a header comment to EACH OF your files, as indicated in your instructions. Here's a link describing the header. Note that headers are not meant to be in Javadoc format. Note that Javadoc is a huge part of your grade for this assignment. Javadoc requires that every class,...
Create a new Java project named Program 4 Three Dimensional Shapes. In this project, create a...
Create a new Java project named Program 4 Three Dimensional Shapes. In this project, create a package named threeDimensional and put all 3 of the classes discussed below in this package Include a header comment to EACH OF your files, as indicated in your instructions. Here's a link describing the header. Note that headers are not meant to be in Javadoc format. Note that Javadoc is a huge part of your grade for this assignment. Javadoc requires that every class,...
Recursion is a programming technique in which a function calls itself. This project applies recursion to a new problem, and illustrates the recursive implementation of backtracking.
RECURSIVELY FINDING PATHS THROUGH A MAZE in C++INTRODUCTIONRecursion is a programming technique in which a function calls itself. This project applies recursion to a new problem, and illustrates the recursive implementation of backtracking.DESCRIPTIONConsider finding all paths from an entrance on the top of a maze to an exit on the bottom. This task can be accomplished recursively, so in this project, you design, implement, test, and document a program that calls a recursive function to find a path through a maze.An...
Recursion Discussions Question: Why would you want to use recursion? Concerning programming, when would you want...
Recursion Discussions Question: Why would you want to use recursion? Concerning programming, when would you want to use iterative vs. recursive programming? Where does coding fit in concerning the software process (i.e. its use in design, in coding, etc.)? Describe recursion problems, and why does it seem to fit with recursion? (e.g. nature, math, music, sports game, etc.)  
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT