Viewing
The goal of this week's lab and project is to build a class for creating and managing the viewing parameters and view transformation matrix.
Tasks
The main result of your work this week should be a View class that holds the current viewing parameters and can build a view transformation matrix [VTM] based on the parameters.

Create a file view.py and begin a class View (you can use any name you
like, but I'll provide some short test programs that assume the class
is named View).
Within the __init__ method, create the following fields and give them the specified default values. You may want to have a reset method, called from __init__ that assigns the default values, as you may want to enable the user to reset the view at any time. Note that the view parameters provide a complete view of the data, looking normal to the XY plane, assuming the data is all located inside the unit cube with one corner on the origin.
 vrp: a NumPy matrix with the default value [0.5, 0.5, 1].
 vpn: a NumPy matrix with the default value [0, 0, 1].
 vup: a NumPy matrix with the default value [0, 1, 0].
 u: a NumPy matrix with the default value [1, 0, 0].
 extent: a list or NumPy matrix with the default value [1, 1, 1]
 screen: a list or NumPy matrix with the default value [400, 400]
 offset: a list or NumPy matrix with the default value [20, 20]

Write a build method that that uses the current viewing
parameters to return a view matrix.

Generate a 4x4 identity matrix, which will be the basis for the view
matrix. For example:
vtm = numpy.identity( 4, float )

Generate a translation matrix to move the VRP to the origin and then
premultiply the vtm by the translation matrix. For example:
t1 = numpy.matrix( [[1, 0, 0, self.vrp[0, 0]], [0, 1, 0, self.vrp[0, 1]], [0, 0, 1, self.vrp[0, 2]], [0, 0, 0, 1] ] ) vtm = t1 * vtm

Calculate the view reference axes tu, tvup, tvpn.
 tu is the cross product (np.cross) of the vup and vpn vectors.
 tvup is the cross product of the vpn and tu vectors.
 tvpn is a copy of the vpn vector.

Normalize the view axes tu, tvup, and tvpn to unit length. You
probably want to write a simple normalize function to handle this.
Make sure you do not include the homogeneous coordinate in the
normalization process. A normalized vector has unit length, and can
be computed as below. (There are more compact ways to do this using
numpy.)
Length = math.sqrt( Vx*Vx + Vy*Vy + Vz*Vz )
Vnorm[0] = Vx / length
Vnorm[1] = Vy / length
Vnorm[2] = Vz / length
 Copy the orthonormal axes tu, tvup, and tvpn back to self.u, self.vup and self.vpn.

Use the normalized view reference axes to generate the rotation matrix
to align the view reference axes and then premultiply M by the
rotation. For example:
# align the axes r1 = numpy.matrix( [[ tu[0, 0], tu[0, 1], tu[0, 2], 0.0 ], [ tvup[0, 0], tvup[0, 1], tvup[0, 2], 0.0 ], [ tvpn[0, 0], tvpn[0, 1], tvpn[0, 2], 0.0 ], [ 0.0, 0.0, 0.0, 1.0 ] ] ) vtm = r1 * vtm

Translate the lower left corner of the view space to the origin. Since
the axes are aligned, this is just a translation by half the extent of
the view volume in the X and Y view axes.
Note that the rest of the project description will use shorthand, rather than writing out the matrices explicitly. Conceptually, the translation is represented as:
vtm = T( 0.5*extent[0], 0.5*extent[1], 0 ) * vtm

Use the extent and screen size values to scale to the screen.
vtm = S( screen[0] / extent[0], screen[1] / extent[1], 1.0 / extent[2] ) * vtm

Finally, translate the lower left corner to the origin and add the
view offset, which gives a little buffer around the top and left edges
of the window.
vtm = T( screen[0] + offset[0], screen[1] + offset[1], 0 ) * vtm
If your code is working properly, then using the default parameters you should get the matrix below.
[[ 400. 0. 0. 20.] [ 0. 400. 0. 420.] [ 0. 0. 1. 1] [ 0. 0. 0. 1.]]

Generate a 4x4 identity matrix, which will be the basis for the view
matrix. For example:
 Create a clone method for your View object that makes a duplicate View object and returns it. That means you need to create a new View object and the manually copy each field from the current View to the new View object.
When you are done with these tasks, go ahead and start the rest of the project.