Homework 2

When you have finished the assignment below, email your source code to the grader at wanghua@cs.nyu.edu. Starting next week, you'll be posting running Java Applets to the Web. For now, you're going to make a stand-alone java application.

As a favor to those of you who have never programmed in Java before, I've done all the structural work for you of building a running application (after all, this isn't a class about learning Java). I've left blank places in the program that you'll need to fill in.

The complete source code follows. Note that the first classes describe general geometric vectors and matrices of length N, and then these classes are extended to the special case of homogeneous vectors and matrices in three dimensional space. Vectors are column vectors, with indices :

0
1
2
3
and I'm adopting the same ordering that the textbook uses (the standard linear algebra convention) for ordering the indices of a matrix, except that I start with 0 instead of 1, to make it easier to program:
0,0 0,1 0,2 0,3
1,0 1,1 1,2 1,3
2,0 2,1 2,2 2,3
3,0 3,1 3,2 3,3

Your job is to:

  1. In all the places where I've put "//...", I'd like you to complete the missing method implementation. I've already done the job for translate, just to get you started.

  2. Since matrices are not commutative, there are actually two different ways to multiply two matrices: you can pre-multiply or post-multiply. I'd like you to fill in the missing implementation for pre-multiply. That's the form of matrix multiplication where the auxiliary matrix is placed to the left of the matrix which is being modified. I've already implemented post-multiply, where the auxiliary matrix is placed to the right of the matrix which is being modified.

  3. I'd like you to figure out whether you should use pre-multiply or post-multiply when implementing the methods for rotate, translate, and scale. Use the one which causes changes to accumulate in the proper order, when the result is used to transform vectors. If you use the wrong kind of matrix multiplication to concatenate your transformations, then when you apply the result to transform a vector you'll get a weird result: as though you had done all your transformations in backwards order.

  4. As extra credit, implement the method for rotation about an arbitrary axis.


import java.util.*;

// Implementation of homogeneous vectors and matrices, with test program.

public class TestMatrices {
   public static void main(String argv[]) {

      Matrix3D m = new Matrix3D();
      Vector3D v = new Vector3D();

      v.set(1, 0, 0);                   // Setting a vector to 1,0,0
      m.rotateZ(Math.PI/2);             // and then rotating
      v.transform(m);
      System.out.println(v.toString());

      m.identity();
                                        // should produce the same result as
      v.set(0, 0, 0);                   // setting the vector to 0,0,0
      m.translate(1, 0, 0);             // then translating by 1,0,0
      m.rotateZ(Math.PI/2);             // and finally rotating.
      v.transform(m);
      System.out.println(v.toString());
   }
}

// Implement geometric vectors of size N

class VectorN {
   private double v[];

   VectorN(int n) { v = new double[n]; }

   int size() { return v.length; }

   double get(int i) { return v[i]; }

   void set(int i, double f) { v[i] = f; }

   void set(VectorN vec) {
      for (int i = 0 ; i < size() ; i++)
	 set(i, vec.get(i));
   }

   public String toString() {                  // string representation "{...}"
      String s = "{";
      for (int j = 0 ; j < size() ; j++)
	 s += ( j == 0 ? "" : "," ) + get(j);
      return s + "}";
   }

   void transform(MatrixN mat) {
      VectorN tmp = new VectorN(size());
      double f;

      for (int i = 0 ; i < size() ; i++) {
	 f = 0.;
         for (int j = 0 ; j < size() ; j++)
	    f += mat.get(i,j) * get(j);
         tmp.set(i, f);
      }
      set(tmp);
   }
}

// Implement geometric matrices of size N x N

class MatrixN { // N x N matrices
   private VectorN v[];

   MatrixN(int n) {
      v = new VectorN[n];
      for (int i = 0 ; i < n ; i++)
	 v[i] = new VectorN(n);
   }

   int size() { return v.length; }

   double get(int i, int j) { return get(i).get(j); }

   void set(int i, int j, double f) { v[i].set(j,f); }

   VectorN get(int i) { return v[i]; }

   void set(int i, VectorN vec) { v[i].set(vec); }

   void set(MatrixN mat) {
      for (int i = 0 ; i < size() ; i++)
	 set(i, mat.get(i));
   }

   public String toString() {                   // string representation "{{..}..{..}}"
      String s = "{";
      for (int i = 0 ; i < size() ; i++)
	 s += ( i == 0 ? "" : "," ) + get(i);
      return s + "}";
   }

   void identity() {                // make this an N x N identity matrix
      for (int i = 0 ; i < size() ; i++)
      for (int j = 0 ; j < size() ; j++)
         set(i, j, (i == j ? 1 : 0));
   }

   void preMultiply(MatrixN mat) {     // mat X this
      //...
   }

   void postMultiply(MatrixN mat) {    // this X mat
      MatrixN tmp = new MatrixN(size());
      double f;

      for (int i = 0 ; i < size() ; i++)
      for (int j = 0 ; j < size() ; j++) {
	 f = 0.;
         for (int k = 0 ; k < size() ; k++)
	    f += get(i,k) * mat.get(k,j);
	 tmp.set(i, j, f);
      }
      set(tmp);
   }
}

// Implement homogeneous vectors in three dimensions

class Vector3D extends VectorN {

   Vector3D() { super(4); }

   void set(double x, double y, double z, double w) {
      set(0, x);
      set(1, y);
      set(2, z);
      set(3, w);
   }
   void set(double x, double y, double z) { set(x, y, z, 1); }
}

// Implement homogeneous matrices in three dimensions

class Matrix3D extends MatrixN {

   Matrix3D() {
      super(4);
      identity();
   }

   void rotateX(double theta) {
      //...
   }
   void rotateY(double theta) {
      //...
   }
   void rotateZ(double theta) {
      //...
   }

   void rotate(Vector3D v, double theta) { // rotate about an arbitrary axis
      // THIS IS FOR EXTRA CREDIT
   }

   void translate(double a, double b, double c) { // translate

      Matrix3D tmp = new Matrix3D();

      tmp.set(0,3, a);
      tmp.set(1,3, b);
      tmp.set(2,3, c);

      postMultiply(tmp); // or should you use preMultiply???
   }
   void translate(Vector3D v) { // translate
      //...
   }

   void scale(double s) { // scale uniformly
      //...
   }
   void scale(double r, double s, double t) { // scale non-uniformly
      //...
   }
   void scale(Vector3D v) { // scale non-uniformly
      //...
   }
}