Homework 2, due Monday, Sept 22.

When you have finished the assignment below, post the working applet onto the web. Post the source code too. Starting this week, please make sure that your web folder for this class contains an index.html page which links to all the assignments for this class, not just for individual assignments. I will link to your main folder from the class page.

This assignment is going to focus on two things:

  1. two dimensional transformation matrices, which can be stored in Java as 3×3 arrays:
       double matrix[][] = new double[3][3];
    
  2. basic user input

For this assignment, I'd like you to make a cool and interesting and creative picture or animation using instances of shapes (ie: show the same shapes translated, rotated, and scaled in different ways). I also want you to use the mouseMove, mouseDown, mouseDrag, mouseUp or keyUp methods (but please don't feel you need to use all of them), to allow the user to interact with your objects in some interesting way, as per our "things" example from class. If you feel more comfortable using the newer Observer based model of input handling instead, please feel free to do so.

You'll find it particularly useful to use the java.awt drawLine, drawPolygon and fillPolygon methods. As we said in class, java.awt methods to draw rectangles and ovals won't really work very well once you start rotating and scaling things.

As we discussed in class, you'll need to implement the following primitive operations:

Identity:
100
010
001
translationMatrix(a,b):
10a
01b
001
rotationMatrix(θ):
cos(theta)-sin(theta)0
sin(theta)cos(theta)0
001
scaleMatrix(a,b):
a00
0b0
001
If it were me, I'd probably implement them all as static methods in a class called Matrix2D, but please feel free to do it another way if you feel confident. The reason I like using static methods for this is that it makes it clear that you don't need to keep any data around by creating object instances.

For example, your method to build a translation matrix might look like this:

public class Matrix2D {

...

   public static void translationMatrix(double matrix[][], double a, double b) {
      identity(matrix);
      matrix[0][2] = a;
      matrix[1][2] = b;
   }
}
You'll also want to implement a method to do matrix multiplication. Remember that you do this by doing nine dot (inner) products. To do this, it's convenient to implement a method that copies the contents of one matrix into another. Then to multiply two matrices A and B:
   copy(A,temp); // FIRST COPY TO A TEMPORARY 3×3 MATRIX
   for (int i = 0 ; i < 3 ; i++)
   for (int j = 0 ; j < 3 ; j++)
      A[i][j] = temp[i][0]*B[0][j] + temp[i][1]*B[1][j] + temp[i][2]*B[2][j];
For convenience, you'll probably want to make methods
   translate(matrix, a, b);
   rotate(matrix, theta);
   scale(matrix, a, b);
which first create the translation, rotation or scale matrix, respectively, and then do a matrix multiply. For example:
   static double tempMatrix[][] = new double[3][3];
   ...
   public static void translate(double matrix[][], double a, double b) {
      translationMatrix(tempMatrix,a,b); // CREATES A TRANSLATION MATRIX
      multiply(matrix, tempMatrix);      // MODIFIES THE FIRST ARGUMENT IN PLACE
   }
Finally, you'll want to implement a method that applies a matrix transformation to a point. Here's how I might implement that:
   public static void transform(double src[], double dst[], double matrix[][]) {
      dst[0] = matrix[0][0] * src[0] + matrix[0][1] * src[1] + matrix[0][2];
      dst[1] = matrix[1][0] * src[0] + matrix[1][1] * src[1] + matrix[1][2];
   }
Now that you have all the tools, you can make pictures that have instances. For example, let's say you define a square shape as:
   double square[][] = {{-1,-1},{1,-1},{1,1},{-1,1}};
Notice that I've used small floating point values for the square vertices. In general you might find it easier to model things in floating point coordinates, with (0,0) at the center of the screen. Then after you do your matrix transformations, you can to a ViewPort transformation to get everything into the proper integer pixel coordinates of your applet window.

You can make all kinds of instances of the square by making transformation matrices and then using them to transform the square. You might find it convenient to keep around a temporary array for the transformed points:

   double xy[][] = new double[100][2];

   ...

   // TRANSFORM ALL THE POINTS
   int len = square.length;
   for (int i = 0 ; i < len ; i++)
      transform(square[i], xy[i], matrix);
as well as temporary arrays for the X and Y pixel coordinates of polygons you want to draw:
   int X[] = new int[100];
   int Y[] = new int[100];
Here's how you might do that ViewPort transformation:
   // DO THE VIEWPORT TRANSFORM AND DRAW A POLYGON
   for (int i = 0 ; i < len ; i++) {
      X[i] = (int)( width/2 * xy[0]) + width/2;
      Y[i] = (int)(-width/2 * xy[1]) + height/2;
   }
   g.drawPolygon(X[i],Y[i],len);
Notice that I've defined the ViewPort transformation so that the origin (0,0) will display at the middle of the screen [width/2,height/2].