LAB 8: Writing Test Programs and Fractals


OBJECTIVE:


The file Polygon.java is a solution to Lab 4.

A. TESTING YOUR CODE

There is an error in this code however which is based on an actual error in one of the submissions of that lab.

This particular error is a runtime NullPointerException. It shows up sometimes inside isCCW(), sometimes in draw(); but usually only when There seems to be some correlation if "makeCCW" is called before calling the other routine.

Write a static function testPolygon() that tests various functions of Polygon with different types of data. Keep a record of the data and the tests with System.out.println(polygon).

Identify AT LEAST two error cases and show this to your TA.

If you are unable to find the bug within one hour, the TAs will tell you where the bug lies. Proceed onto B, and post the finished testPolygon() function on your web page later. Along with it, please put up some of the more interesting test cases on your web page.

B. FRACTAL triangles.

Design and implement a method equiTriangleFractal that draws the shape shown. Note that this is drawn by recursively invoking equiTriangleFractal( ??). What are the method variables needed? What is the exit condition? (See the two images below and think about it). You may wish to write a more general TriangleFractal() method which is called by equiTriangleFractal(). Make sure your code is javadoc-commented.

Please put up your results as .gif files (use xview or some other program to capture the screen) on your web page. Then point your friends and family to your web page to show what great work you are doing at IITK!!


Two outputs from equiTriangleFractal() at two different exit conditions.

Clearly every recursive call should shift the center (or vertices) of the triangle, and also re-size it. The exit condition would have to do with the size of the triangle.


The file Polygon.java
uses the class Canvas.java

.

Polygon.java

/* =================   FILE Polygon.java (A)  ================= */
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;

/**
 class Polygon defines a polygon, and includes methods for testing if
 it is convex, CounterClockWise, etc. 

 It also has routines for drawing polygons (using Canvas) and for
 printing polygons (using System.out).

 @author Amitabha Mukerjee 
 @version 24.08.2002
 */

public class Polygon
{
    private Point2D.Double[] vertex;
    private int numVertices;
    private String color="black"; 

    /**
       Default Constructor; create an array of vertices
       @param n number of vertices
    */
    public Polygon(int n)
    {
        vertex = new Point2D.Double[n];
        numVertices = 0;
    }

    /**
       Add vertex coordinates for the next vertex; 
       @param Point2D  next vertex coordinates
    */
    public void add(Point2D.Double p)
    {
        if (numVertices < vertex.length)
        {
            vertex[numVertices] = p;
            numVertices++;
        }
    }

    /**
       Change n-th vertex coordinates; 
       @param n vertex to change
       @param Point2D new vertex coordinates
    */
    public void change(int n, Point2D.Double p)
    {
        if (n < vertex.length)
        {
            vertex[n] = p;
        }
    }
    
    /** REWRITE THIS ROUTINE (and this comment) TO TEST THE VARIOUS METHODS */
    public static void testPolygon()
    {
    }

    /**
       True if p1p2 to p2p3 constitutes a Left Turn.  It is a left
       turn if the CrossProduct p1p2 x p2p3 has a +ve z component, i.e.
       if the determinant ( p1.x p1.y 1 , p2.x p2.y 1, p3.x p3.y 1) is +ve. 

       NOTE: A better name for this method may be boolean turnLeft()

       @param p1,p2,p3 - three points
    */
    public static boolean turnTest( Point2D.Double p1, Point2D.Double p2, 
    Point2D.Double p3) 
    {
        double x1 = p1.getX();        double y1 = p1.getY();
        double x2 = p2.getX();        double y2 = p2.getY();
        double x3 = p3.getX();        double y3 = p3.getY();
        return ( (x2 - x1) * (y3 - y2) - (x3-x2) * (y2-y1)  > 0 );
    }

    /**
       Test if the polygon is Convex. 
       It is convex if all vertices are turns in the same direction.
    */
    public boolean isConvex()
    {
        Point2D.Double prev = vertex[numVertices-2];
        Point2D.Double curr = vertex[numVertices-1];
        Point2D.Double next = vertex[0];
        
        boolean isCCW = turnTest (prev, curr, next); 

        for (int i = 1; i < numVertices; i++)
        {
            prev = curr;
            curr = next;
            next = vertex[i];
            if (turnTest (prev, curr, next) != isCCW ) 
                return (false);
        }
        return (true);
    }

    /**
       Test if the polygon is CounterClockWise. 
       It is CCW if the vertex with lowest Y is CCW. 
    */
    public boolean isCCW()
    {
        double min = vertex[0].getY();
        int minIndex = 0;
        for (int i = 1; i < numVertices; i++)
        {   if (vertex[i].getY() < min)
            { 
                min = vertex[i].getY() ;
                minIndex = i;
            }    
        }
        Point2D.Double prev = vertex[(minIndex - 1 + vertex.length) % vertex.length ]; 
        Point2D.Double next = vertex[(minIndex + 1) % vertex.length ];
        return (turnTest (prev, vertex[minIndex], next));
    }

    /**
       If the polygon is ClockWise, reverse its vertex order to make it CCW.
    */
    public void makeCCW()
    {
        if (!isCCW())
        { 
            Polygon reverse = new Polygon(numVertices);        
            for (int i = numVertices-1; i > 0 ; i--)
            {   reverse.add(vertex[i]);
            }
            for (int i = 0; i < numVertices; i++ )
                vertex[i]=reverse.vertex[i];
        }
    }

    /** The "toString()" method is used by System.out to 
        display the object data on the console.
  
        It will invoked when you call 
                System.out.println(polygonName);
    */
    public String toString()
    {
        String s="";
        for (int i = 0; i < numVertices; i++)
        {   s += ("Vertex " + i + ": " + vertex[i] + "\n");
        }
        return s;
    }

    /**
        Change the color. 
        @param newColor Valid colors are "red", "yellow", "blue", "green",
            "magenta" and "black".
     */
    public void changeColor(String newColor)
    {
        color = newColor;
        draw();
    }

    /**
       Draw the polygon
    */
    public void draw()
    {
        Point2D.Double from = vertex[numVertices-1];
        Point2D.Double to;

        Canvas canvas = Canvas.getCanvas();
        canvas.setForegroundColour(color);
        for (int i = 0; i < numVertices; i++)
        {
            to = vertex[i];
            canvas.draw(new Line2D.Double(from, to));
            canvas.wait(10);
            from = to;
        }
    }
}