1

I have two classes a 3D vector class(Vector3) with an array of 3 floats as its member(float[3]), and a 3 by 3 matrix class that stores 3 of these vectors in another array(Vector3[3]). My vector class requires the matrix class to rotate about an axis, and my matrix class requires vectors for everything. I was using forward declarations and pointers to deal with it, like in this question: What is the best way to deal with co-dependent classes in C++?, but there must be a better way to design this to avoid that altogether. At the moment I declare a pointer to Vector3 on my matrix header file, and then initialize it with new in my implementation file, yet this feels clumsy. Any pointers(no pun) on how to solve this issue? Edit: I use the vector class to represent a 3D point which I intend to rotate about an arbitrary axis.

The code as I would like it to work:

    //Vector3.h

    #include "Matrix3.h"
    class Matrix3;

    class Vector3 {
      float xyz[3];
    };

    //Vector3.cpp

    Vector3 Vector3::rotatePoint(Vector3 o, Vector3 a,  float theta) {

Vector3 point = (*this);
Vector3 x = Vector3(1,0,0);
Vector3 y = Vector3(0,1,0);
Vector3 z = Vector3(0,0,1);

// Create new coordinate system
Vector3 new_coord[4];
new_coord[0] = o;
new_coord[1] = a.normalize();

unsigned closer_to;
if (a*x < a*y) {
    new_coord[2] = (a % x).normalize();
    closer_to = 0; // x
}
else {
    new_coord[2] = (a % y).normalize();
    closer_to = 1; // y
}
new_coord[3] = (a % new_coord[2]).normalize();

// Transform point to new coord system
Matrix3 trans_matrix = Matrix3(new_coord[0], new_coord[1], new_coord[2]);
point = trans_matrix*(point - o);

// Rotate about a by theta degrees
Matrix3 r_m(closer_to, theta);
point = r_m*point;

//Transform back to original coord system
point = (trans_matrix.inverse()*point) + o;
return point;
}        
    //Matrix3.h

    #include "Vector3.h"

    class Vector3;

    class Matrix3 {
       Vector3 rows[3];
    }

The code that I use to make it work:

    //Vector3.h

    class Matrix3;

    class Vector3 {
      float xyz[3];
    };

    //Matrix3.h

    #include "Vector3.h"

    class Vector3;

    class Matrix3 {
       Vector3 *rows;
    }

    //Matrix3.cpp

    Matrix3::Matrix3() {
        rows = new V3[3];
    }
Community
  • 1
  • 1
  • 2
    The vector class should not have a dependency on the Matrix class. Why does vector rotation rely on a matrix? – Egg Sep 12 '14 at 16:10
  • @Egg Check my edit.I use a matrix to convert the point to a new coordinate system, a rotation matrix to do the rotation and then I bring back the point to the original coordinate system. I was thinking that maybe rotation shouldn't be on the vector class but I don't know where to put it, and it will be a common operation on them. – Leo Azopardo Sep 12 '14 at 16:20
  • A `Vector` does not *contain* a `Matrix`, so the `Vector` declaration only needs a forward-declaration of `Matrix` (if any). A `Matrix` contains three `Vector`s so there is a full-blown dependency. – n. m. could be an AI Sep 12 '14 at 16:23
  • @n.m. If I don't include `Matrix` on my vector declaration then I get an incomplete type error. – Leo Azopardo Sep 12 '14 at 16:30
  • It does sound like you have a valid case for co-dependency. I would only move rotation out of the vector if you've got a single class in your architecture where all vector rotation would occur. – Egg Sep 12 '14 at 16:31
  • You are not passing your `Matrix` by value, are you? – cmaster - reinstate monica Sep 12 '14 at 16:31
  • How about representing a Vector as a special kind of a Matrix? then you have one class (Matrix) and a Vector as subclass if you wish. – Ashalynd Sep 12 '14 at 16:41
  • @cmaster to my rotation function? No, I don't pass a matrix to it, I create two matrices inside it. – Leo Azopardo Sep 12 '14 at 16:50
  • Keep the two classes and implement all operations requiring both after the definition of vector and matrix as (inline) freestanding functions or member functions. Neither, should have a data member of the other. –  Sep 12 '14 at 16:52
  • 1
    Take the code 'as you would like it to work', delete the `#include "Matrix3.h"` line from `Vector3.h` -- done. All should work fine now. If not, you have some other weird dependendency you should not have that you haven't shown – Chris Dodd Sep 12 '14 at 17:12
  • @DieterLücking How would I go about that? Put the rotation on my main file? They are currently member functions. – Leo Azopardo Sep 12 '14 at 17:13
  • You are not using Matrix in Vector3.h. Why ever reference it? – n. m. could be an AI Sep 12 '14 at 17:14
  • @n.m. I do, inside the rotation function. – Leo Azopardo Sep 12 '14 at 17:18
  • There is no rotation function I can see. I have asked you to show your code, not irrelevant fragments of your code. Thank you. – n. m. could be an AI Sep 12 '14 at 17:21
  • @n.m. Just put it there. – Leo Azopardo Sep 12 '14 at 17:30
  • You have Matrix in Vector3.cpp, so include Matrix3.h in Vector3.cpp. – n. m. could be an AI Sep 12 '14 at 17:31
  • @n.m. the main problem is on the matrix declaration where I get the incomplete type error if I don't use a pointer and dynamic allocation. So there really is no elegant way to solve this? – Leo Azopardo Sep 12 '14 at 17:57
  • 1
    Your problem is circular includes. Vector3.h includes Matrix3.h and Matrix3.h includes Vector3.h. *This never works*. Remove `#include "Matrix3.h"` from Vector3.h, and the problem disappears. – n. m. could be an AI Sep 12 '14 at 18:01
  • Go with Chris Dodd's and n.m.'s advice, and you should be fine. However, there is not even a point in forward declaring `Matrix3` in "Vector3.h" if that *header* does not use the symbol. Just include "Matrix3.h" in "Vector3.cpp". The less includes you do from a header, the less likely you get circular inclusion problems. – cmaster - reinstate monica Sep 13 '14 at 07:26

2 Answers2

0

I took the advice given by @n.m. and @Chris Dodd's and just removed the Matrix3 include from my Vector header, and into my Vector implementation file, like this:

    //Vector3.h

    class Vector3 {
        float xyz[3];
    }

    //Vector.cpp

    #include "Vector3.h"
    #include "Matrix3.h"

    //Matrix3.h

    #include "Vector3.h"
    class Vector3;

    class Matrix3 {   
        Vector3 rows[3];
    }

    //Matrix3.cpp

    #include "Matrix3.h"
0

Since you're dealing with vectors and matrices, you could define a single matrix class with templates for the dimensions (and maybe the element type) -- the vector class would then (depending on the type of vector) be a matrix with one of the dimension = 1. If you do this, you only end up with one class, one set of code and all the functionality required to do everything you want. You avoid any inter-class dependencies since you only have one class!

The class itself would look something like this:

template<unsigned m, unsigned n, typename T = float>
class matrix {
    T e[m * n];
public:
   T* operator [](unsigned i) { return e + i; }
   T * const operator [](unsigned i) const { return e + i; }
   /* repeat for -, *, / -- same pattern */
   matrix<m,n>& operator += (matrix<m,n> const& a) {
        for (unsigned i = 0; i < m * n; ++i) e[i] += a.e[i];
        return *this;
   }
};

You should then define any functions which does not take equal sized matrices outside the class (this is why we have the [] operator). Note that the * and / operators work on all elements and do not calculate the usual matrix-matrix multiplication or matrix-matrix division. Instead, you will want to have a invert function and a multiply function.

template<unsigned m, unsigned n, unsigned k>
matrix<m,k> const multiply(matrix<m,n> const& a, matrix<n,k> const& b);

template<unsigned m>
matrix<m,m> const invert(matrix<m,m> const&);

template<unsigned m, unsigned n>
matrix<n,m> const transpose(matrix<m,n> const&);

Note that, if you have a method for inverting a generic non-square matrix, of which I know none, the above template will only work for a square matrix. Filling in the code for the functions I leave to you as an exercise.

To get a 3 vector and a 3x3 matrix, you could typedef them as so:

typedef matrix<3,1,float> vector3f;
typedef matrix<3,3,float> matrix3x3f;

Remember to add comparison operators as well as anything else you need.

If you wish, you could add matrix-scalar and scalar-matrix operators and functions as well (to ease, say, adding a scalar to all the elements in a matrix).

If you want better control over the elements in the [] operators, you could use vectors as the base class and then define matrices as a vector of vectors. This will give you the same advantages but may suit your mindset more easily (a lot of people think of vectors and matrices as being distinct types).

Clearer
  • 2,166
  • 23
  • 38