next up previous
Next: t_see_world Up: t_see_world Previous: t_see_world

8.2. Using more advanced ideas
Functions
The program above is crying out for some functions. Too many pieces of it are repetitive--converting degrees to radians, making rotation matrices, etc. Repetition leads to small editing errors that are easy to miss.

[Classes] It isn't easy to have a function return an array as a value; you'd need to allocate the space for the array. It's easier to use classes.

Some class declarations are suggested below. To keep things easy, let's use a vector class vec3 and a matrix class mat33 for three dimensions only, which means that memory allocation issues can be avoided entirely.

With a class, you can still define [] so the result looks like an array: R[i][j] and so on. You can also define * for matrices times matrices and vectors times matrices so that you can write R = A*B for matrices.

Suggested classes, in outline:

class vec3
{
        double ent[3];                          // entries
        friend ostream& operator<<(ostream&, const vec3&);
public:
        vec3();                                 // (set entries to 0)
        vec3(double a, double b, double c){ ent[0]=a; ent[1]=b; ent[2]=c; }
        vec3( const vec3& v );                  // copy constructor
        // no destructor necessary
        vec3& operator=( const vec3& v );       // assignment
        double& operator[](int i);       //  so can say  v[i] = 3, etc.
};                                       //  (be sure to check 0 <= i < 3)

ostream& operator<<(ostream& o, const vec3& v);

class mat33
{
        vec3 rows[3];
        friend ostream& operator<<(ostream&, mat33&);
public:
        mat33(){}                          // (entries will already be 0)
        mat33( const mat33& m );           // copy constructor
        // no destructor necessary
        mat33& operator=(const mat33& m);  // assignment
        vec3& operator[](int i);   // so m[i] means a row, m[i][j] an entry
        mat33 operator*(const mat33& m);   // returns this mat times m
        mat33 transpose();                 // returns transpose of this mat
};

mat33 identity33();

mat33 rot3(double theta, int i_from, int i_to);

vec3 operator*(const vec3& v, const mat33& m);

vec3 cartesian(double latitude, double longitude);  // (can use prev fns)

ostream& operator<<(ostream& o, const mat33& m);

Of course, you will need to supply expansions for functions, either in-line or separately.

Be sure to include any headers needed.

Technically, in the classes above, whenever a method does not change any class member it is best to tag it with const, as in mat33 transpose() const;

Here are expansions of the identity() and rot3 functions--but let's use the name identity33() instead.

mat33 identity33()
{
    mat33 M;                    // entries start out 0
    for (int i=0; i<3; i++)
        M[i][i] = 1.0;
    return M;
}

mat33 rot3(double theta, int i_from, int i_to)
{
    mat33 M = identity33();
    M[i_from][i_from] = cos(theta);
    M[i_to][i_to]     = cos(theta);
    M[i_from][i_to]   = sin(theta);
    M[i_to][i_from]   = -sin(theta);
    return M;                           // don't forget this line!
}

In writing the rot3 function, to keep things straight just focus on the case where i_from is 0 (x) and i_to is 1 (y). Notice that the rot3 function works correctly no matter whether you want rot3(theta,x,y) or rot3(theta,y,x) .

Assuming you have also included the matrix multiplication routine as a member function of mat33, namely

mat33 operator*(mat33 m) or better,

mat33 operator*(const mat33& m), you can now say simply

mat33 R = rot3(view_long_rad + pi/2,y,x) * rot3(pi/2 - view_lat_rad,z,y);




next up previous
Next: t_see_world Up: t_see_world Previous: t_see_world
Kirby A. Baker 2002-02-21