A CLASS FOR REGULAR POLYGONS

Please turn in your hypotheses before the start of lab.


In this lab, you will learn more about abstract methods and some of the details involved in drawing figures.

RegularPolygon and Square Classes

So far in your Java journey, every method has been completely defined -- that is, ready to be invoked by an object, or for static methods, by the class itself. There are occasions when a method heading will be provided in a class, but the complete definition will be supplied in the subclasses.

For example, suppose we are developing a RegularPolygon class. A polygon, from the Greek for "many angles", is a closed plane figure bounded by straight lines. A regular polygon is one in which all the sides have the same length and all of the interior angles are equal. For example, a square is a regular polygon.

The methods we want in the class RegularPolygon are:

area(), which returns the area of the polygon;

perimeter(), which returns the distance around the polygon;

toString(), which returns a string describing the polygon;

draw(), which draws the polygon.

We will have two fields, numberOfSides and sideLength. The numberOfSides field should certainly be an int. We choose to make sideLength an int also, in order to simplify the drawing of the polygon. So you can think of the units as pixels, that is, picture elements. The number of pixels per inch will vary depending on your monitor. Given the number of sides and the length of each side, we can immediately calculate the perimeter, so we have:

/**
 *  Calculates and returns the polygon's perimeter.
 *
 *  @return a final int holding the value of the polygon's perimeter
 **/
public final int perimeter()
{
    return numberOfSides * sideLength;
} // method perimeter

This method will be used unchanged by all of the subclasses of RegularPolygon. The modifier final indicates that subclasses of RegularPolygon do not have the option of altering this method.

The toString method will describe the regular polygon. Some of the information will be supplied in this method, and the rest in the appropriate subclass's toString method. For this application, we could have supplied all of the information in the subclass, but instead we chose to illustrate a situation in which the superclass has some of the information and the subclasses have the rest of the information.

The draw and area methods are more appropriately handled by the subclasses. For example, a square would draw itself differently from the way an equilateral triangle would draw itself. So the draw and area methods will be abstract methods in the RegularPolygon class. For an abstract method, the method heading must include the abstract modifier, and the method heading is immediately followed by a semicolon. Here is the complete RegularPolygon class -- an abstract class because it contains at least one abstract method. Please study this class for two minutes.

abstract public class RegularPolygon 
{
  protected int numberOfSides;
  
  protected int sideLength;
  
  public abstract int area();
  
  public abstract void draw();
  
  
  /**
   *  Creates a string representation of the polygon
   *
   *  @return a String representing the polygon, for output
   **/
  public String toString() 
  {
    final String POLYGON = "This is a regular polygon";
    
    return POLYGON;
  } // method toString
  
  
  /**
   *  Calculates and returns the polygon's perimeter.
   *
   *  @return a final int holding the value of the polygon's perimeter
   **/
  public final int perimeter() 
  {
    return numberOfSides * sideLength;
  } // method perimeter
  
} // class RegularPolygon


Notice that the methods area and draw have the abstract modifier, indicating the definitions for these methods will be found in the subclasses. What is the significance of the fact that RegularPolygon is an abstract class, that is, a class with at least one abstract method? An abstract class cannot be instantiated. That is, we cannot do the following:

RegularPolygon polygon = new RegularPolygon();

This makes sense because an abstract class has at least one undefined method. However, as we will need later, the following is legal:

RegularPolygon polygon;

This allows polygon to be a (polymorphic) reference to any object in any class that inherits RegularPolygon.

The Square class is fairly straightforward. Note that, in the toString method, the return statement starts by calling the superclass's version of the toString method. The super reserved word is used to refer to the superclass's version of a method.

public class Square extends RegularPolygon 
{
  public Square() { }
  
  /**
   *  Initializes a square from length.
   *
   *  @param length an int holding the length of an edge
   **/
  public Square (int length) 
  {
    numberOfSides = 4;
    sideLength = length;
  } // constructor
  
  
  /**
   *  Creates a string representation of the square
   *
   *  @return a String representing the square, for output
   **/
  public String toString() 
  {    
    final String SQUARE = ": a square with side length "; 
    
    return super.toString() + SQUARE + sideLength;    
  } // method toString
  
  
  /**
   *  The area of the square is calculated and returned.
   *
   *  @return an int holding the value of the square's area
   **/
  public int area() 
  {  
    return sideLength * sideLength; 
  } // method area
  
  
  /**
   *  The square is drawn.
   **/
  public void draw() 
  {  
    ArtFrame frame = new ArtFrame();
    
    final int START_X = 20;  // the x co-ordinate of the upper
    // left corner of the square
    final int START_Y = 20;  // the y co-ordinate of the upper
    // left corner of the square
    
    frame.drawLine (START_X, START_Y, START_X + sideLength, START_Y);
    frame.drawLine (START_X, START_Y, START_X, START_Y + sideLength);
    frame.drawLine (START_X + sideLength, START_Y,
                    START_X + sideLength, START_Y + sideLength);
    frame.drawLine (START_X, START_Y + sideLength,
                    START_X + sideLength, START_Y + sideLength);
  } // method draw
  
} // class Square

As you can see, the actual drawing of lines takes place in the ArtFrame class. Recall (or note) that a GUI window uses an X, Y coordinate system, with (0,0) representing the location of the pixel in the upper-left-hand corner. The location of the pixel 10 units to the right and 30 units down from that origin has coordinates (10, 30), not (10, -30) -- so the Y values increase as you go down the window.

The area and draw methods in the EquilateralTriangle class require some explanation. The key calculation for both methods is the height of the equilateral triangle. If a line is drawn from a vertex to the midpoint of the opposite side, two right triangles are formed, and the length of the newly drawn line is the height of the equilateral triangle. For either right triangle, the hypotenuse is sideLength, one of the other sides has length sideLength / 2, and the other side has length height. The Pythagorean Theorem applies, and the height is sideLength * sqrt (3) / 2, truncated to an int.