# Vector/matrix class

Some definitions:

#define _count(total) for (int count = 0; count < total; count++)

#define _xyCount(x,y) \
for (int xCount = 0; xCount < x; xCount++) \
{for (int yCount = 0; yCount < y; yCount++){

#define _xy }}


I just use these to save time. The _xy is used cause if I don't, VS will act weird. Now for the vector and matrix. I've created a number of different kinds of vectors and matrices and I post these as the general form.

struct vector3
{
double e;

///////////////////////////

vector3 operator/(double d)
{
vector3 out;
_count(3)
{
out.e[count] = e[count] / d;
}
return out;
}

vector3 operator*(double d)
{
vector3 out;
_count(3)
{
out.e[count] = e[count] * d;
}
return out;
}

vector3 operator-(vector3 vec)
{
vector3 out;
_count(3)
{
out.e[count] = e[count] - vec.e[count];
}
return out;
}

vector3 operator+(vector3 vec)
{
vector3 out;
_count(3)
{
out.e[count] = e[count] + vec.e[count];
}
return out;
}

double operator*(vector3 vec)
{
double out;
_count(3)
{
out += e[count] * vec.e[count];
}
return out;
}

vector3 operator%(vector3 vec)///-cross product
{
vector3 out;

out.e = e * vec.e - e * vec.e;
out.e = e * vec.e - e * vec.e;
out.e = e * vec.e - e * vec.e;

return out;
}

////////////////////////////

vector3()
{
e = e = e = 0;
}
~vector3(){}
}; typedef vector3 v3_;


This is the 3 by 3 matrix:

struct matrix_3x3
{
double e;

///----------------

matrix_3x3 operator/(double d)
{
_xyCount(3,3)

e[xCount][yCount] /= d;

_xy

}

///----------------

matrix_3x3 operator*(double d)
{
_xyCount(3,3)

e[xCount][yCount] *= d;

_xy

}

///----------------
///-?
vector3 operator*(vector3 v)
{

vector3 out;

_xyCount(3,3)

out.e[xCount] += v.e[yCount] * e[xCount][yCount];

_xy

return out;

}

///----------------

matrix_2x2 minorAltB(int column, int row)
{

matrix_2x2 out;

///----------------------------
int x, y;
x = y = 0;

_xCount(2)
{
y = 0;

if (xCount == column)
{
x = 1;
}

_yCount(2)
{

if (yCount == row)
{
y = 1;
}

out.e[xCount][yCount] = (int)(e[xCount + x][yCount + y]);

}

}
///----------------------------

return out;

}

matrix_2x2 minorAlt(int column, int row)
{

matrix_2x2 m;
int x, y;
x = y = 0;

_xyCount(3,3)

if (xCount != column)
{

y = 0;

if (yCount != row)
{

m.e[x][y] = (int)(e[xCount][yCount]);

y = 1;

}

x = 1;

}

_xy

}

matrix_2x2 minor(int column, int row)
{

matrix_2x2 out;

double temp;

int count;

_xyCount(3,3)

if (xCount != column)
{
if (yCount != row)
{
temp[count] = e[xCount][yCount];
count++;
}
}

_xy

out.e = (int)temp; out.e = (int)temp;
out.e = (int)temp; out.e = (int)temp;

}

double det()
{
return minor(0,0).value() - minor(1,0).value() + minor(2,0).value();
}

matrix_3x3 transpose()
{
matrix_3x3 out;

_xyCount(3,3)

out.e[xCount][yCount] = e[yCount][xCount];
_xy
return out;
}

bool invert()
{
double d = det();

if (d == 0)
{
return false;
}
else
{
matrix_3x3 m, t, i;

double sign = 1;

_xyCount(3,3)

m.e[xCount][yCount] = minor(xCount,yCount).value() * sign;

sign *= -1;

_xy

t = m.transpose();

i = t / d;

*this = i;

return true;
}

}

///-------------------

matrix_3x3( double ax, double ay, double az,
double bx, double by, double bz,
double cx, double cy, double cz)
{
e = ax; e = ay; e = az;
e = bx; e = by; e = bz;
e = cx; e = cy; e = cz;
}

matrix_3x3()
{
_xyCount(3,3)

e[xCount][yCount] = 0;
_xy
}

~matrix_3x3()
{

}

}; typedef matrix_3x3 m33_;


I've created 3 functions to get minors but haven't decided which one to go with.

Here is the 3D point, ray and triangle:

///+++++++++++++++++++++++++++++++++\
///     point3                       }
///+++++++++++++++++++++++++++++++++/
struct point3 : public v3_
{
///-nothing yet

double x()
{
return e;
}

double y()
{
return e;
}

double z()
{
return e;
}

///------------------------------

void x(double n)
{
e = n;
}

void y(double n)
{
e = n;
}

void z(double n)
{
e = n;
}

///------------------------------

void xyz(double X, double Y, double Z)
{
e = X; e = Y; e = Z;
}

///------------------------------

double abs()
{
return cSqrt(_sq(e) + _sq(e) + _sq(e));
}

double getDistance(point3 from)
{
point3 diff;

diff.x(x() - from.x());
diff.y(y() - from.y());
diff.z(z() - from.z());

return diff.abs();

}

///------------------------------

void operator=(vector3 v)
{
x(v.e); y(v.e); z(v.e);
}

point3 operator+(point3 p)
{
point3 out;
out.e = e + p.e;
out.e = e + p.e;
out.e = e + p.e;
return out;
}

point3 operator-(point3 p)
{
point3 out;
out.e = e - p.e;
out.e = e - p.e;
out.e = e - p.e;
return out;
}

point3 operator/(double d)
{
point3 out;
out.e = e / d;
out.e = e / d;
out.e = e / d;
return out;
}

point3 operator*(double d)
{
point3 out;
out.e = e * d;
out.e = e * d;
out.e = e * d;
return out;
}

double operator*(point3 p)
{
double out;
_count(3)
{
out += e[count] * p.e[count];
}
return out;
}

point3 operator%(point3 p)
{
point3 out;

out.e = e * p.e - e * p.e;
out.e = e * p.e - e * p.e;
out.e = e * p.e - e * p.e;

return out;
}

///------------------------------

point3(double a, double b, double c)
{
e = a; e = b; e = c;
}

point3(){}
~point3(){}
};
typedef point3 p3_;

point3 origin3(0,0,0);
///||||||||||||||||||||||||||||||||||

///+++++++++++++++++++++++++++++++++\
///     ray                          }
///+++++++++++++++++++++++++++++++++/
struct ray : public m32_
{

///-----------------------------

p3_ A()
{
p3_ out;
out.x(e); out.y(e); out.z(e);
return out;
}

p3_ B()
{
p3_ out;
out.x(e); out.y(e); out.z(e);
return out;
}

void A(p3_ a)
{
e = a.x(); e = a.y(); e = a.z();
}

void B(p3_ a)
{
e = a.x(); e = a.y(); e = a.z();
}

void AB(p3_ a, p3_ b)
{
A(a); B(b);
}

///-----------------------------

p3_ B_A()
{
p3_ out;
out = B() - A();
return out;
}

double length()
{
return B_A().abs();
}

ray getUnit()
{
ray out;

out.B(A() + (B_A() / length()));

return out;
}

p3_ getUV()
{
return getUnit().B_A();

}

///-----------------------------

ray(p3_ a, p3_ b)
{
A(a); B(b);
}
ray(){}
~ray(){}

};
///||||||||||||||||||||||||||||||||||

///+++++++++++++++++++++++++++++++++\
///     triangle3                    }
///+++++++++++++++++++++++++++++++++/
struct triangle3 : public m33_
{
Uint32 color;

///-------------------------------

p3_ A()
{
p3_ out;
_count(3)
{
out.e[count] = e[count];
}
return out;
}

p3_ B()
{
p3_ out;
_count(3)
{
out.e[count] = e[count];
}
return out;
}

p3_ C()
{
p3_ out;
_count(3)
{
out.e[count] = e[count];
}
return out;
}

///-------------------------------

void A(p3_ in)
{
_count(3)
{
e[count] = in.e[count];
}
}

void B(p3_ in)
{
_count(3)
{
e[count] = in.e[count];
}
}

void C(p3_ in)
{
_count(3)
{
e[count] = in.e[count];
}
}

///-------------------------------

p3_ P(int p)
{
p3_ out;
_count(3)
{
out.e[count] = e[count][p];
}
return out;
}

void P(int p, p3_ in)
{
if (p >= 3)
{
///-do nothing
}
else
{
_count(3)
{
e[count][p] = in.e[count];
}
}
}

///-------------------------------
///-find the angle at vertex A
double ang()
{
///-two vectors 'lines' on either side of vertex A
p3_ b, c;

///-subtract A from each vertex to get required vectors
c = B() - A();
b = C() - A();

///-get the dot product 'dp'
double dp = b * c;

///-get the lengths of each line
double bAbs = b.abs();
double cAbs = c.abs();

///-out set at 1000 for error check
double out = 1000;

///-dbz check
if (bAbs != 0 && cAbs != 0)
{
///- b * c = bc(Cos(A))
out = acos(dp / (bAbs * cAbs));
}

return out;

}

///-find the angle at any vertex
double ang(int p)
{
int i;

double out = 1000;

p3_ temp;

_count(3)
{

if (count != p)
{
temp[i] = P(count);
i++;
}

}

_count(2)
{
temp[count] = temp[count] - P(p);
}

double dp = temp * temp;
double absB = temp.abs();
double absC = temp.abs();

if (absB != 0 && absC != 0)
{
out = acos(dp / (absB * absC));
}

return out;

}

///-------------------------------

///-find the center of the triangle
p3_ center()
{
p3_ out;

double X, Y, Z;

_count(3)
{
X += e[count];
Y += e[count];
Z += e[count];
}

out = out / 3;

return out;

}

p3_ normalAlt(int v = 0, bool added = false)
{
p3_ out;

p3_ *others;

_count(3)
{
if (count != v)
{
*others = P(count);
others++;
}
}

{
out = P(v) + ((others - P(v)) % (others - P(v)));
}
else
{
out = (others - P(v)) % (others - P(v));
}
return out;
}

p3_ normal()
{

return (B() - A()) % (C() - A());

}

p3_ bounce(p3_ in, int vertex = 0)
{
p3_ out;

out = in;

p3_ left, forward;

p3_ n = normal();

p3_ diff;

if (vertex > 2 || vertex < 0)
{
return in;
}

diff = in - P(vertex);

left = diff % n;

forward = left % n;

ray u(in, in + forward);

u = u.getUnit();

p3_ in_A = in - A();

double den = in_A.abs() * n.abs();

if (den == 0)
{
return in;
}

out = in + in_A * 2 * (cSqrt(1 - (_sq((in_A % n) / den))));

return out;
}

triangle3 reflect(p3_ pov)
{
triangle3 out;

_count(3)
{
out.P(count,bounce(pov,count));
}

return out;
}

///-------------------------------

double getDistance(p3_ p)
{
double out;

ray r;

r.AB(p, A());

out = r.length();

r.B(B());

if(out > r.length())
out = r.length();

r.B(C());

if(out > r.length())
out = r.length();

return out;
}

///-------------------------------

triangle3(p3_ a, p3_ b, p3_ c)
{
A(a); B(b); C(c);
}

triangle3()
{
color = WHITE;
}
~triangle3(){}

};
typedef triangle3 t3_;
///||||||||||||||||||||||||||||||||||


I've actually used this to raytrace successfully and render a reflected circular light onto a polygon. Unfortunately, it took almost ten seconds to render so I must be doing something wrong. If there's a good matrix/vector library out there I might use someone else's code. If this is the best I can get, I want to figure out how to make a matrix of varying dimensions.

A few aesthetic points worth mentioning:

• I find those _count and _xy macros to be a terrible idea. They greatly obfuscate the code and are very fragile constructs. It is very easy to break them. Just use plain for loops. It will be a lot more straightforward.

• Names stating with an underscore, in the global namespace, are a bad idea. Read more about it here.

• An empty destructor is pointless. Omit the destructor if the class doesn't require special cleanup.

• Apparently pointless typedefs? Why did you typedef vector3 to v3_ and matrix_3x3 to m3_? That seems like just more code obfuscation that hurts readability.

• There are consecutive blank lines in some places. This makes your code look untidy.

• A suggestion on naming convention: PascalCase is more popular for type names, while camelCase is frequently used for method and variable names.

• Thank you for your reply: I remember hearing about the dangers of leading underscores a while back. Now I'll remember not to use them. Are empty constructor's just as pointless? I use v3_ and m33_ just to save space. If I write a function with lots of arguments, my ocd acts up when it wraps to the next line. And I use the blanks just to keep separate things more clearly separated. It's easier for me to read. When you say type names, you mean class names, right? – Mindril Nov 25 '14 at 17:29
• @Mindril - Yes, an empty constructor is also unnecessary. My problem with the two names for the same thing is that it can be a source of confusion. Some might think vector3 and v3_ are different things. Why not make a compromise and replace both with Vec3 perhaps? No problem with spacing the code well, but avoid multiple consecutive blank lines. Those look unnatural. By type names I mean class, struct, typedef, and such. – glampert Nov 25 '14 at 17:40
• Empty constructors are actually slightly different to an undefined constructor. As the compiler will generate two versions of a default constructor (one is used for value initialization the other being used for zero initialization). If your class contains any POD members (or has a member or inherits from a class with POD members and a compiler generated constructor) then the only safe thing to do is have a constructor that specifically initializes POD members (this includes arrays of integers). – Martin York Nov 25 '14 at 21:13
• Yes, indeed, very well noted @LokiAstari. – glampert Nov 25 '14 at 21:15

I'm toying around with this idea:

template <typename type>
class matrix_AxB
{
unsigned int rows, columns;

public:

type *e;

matrix_AxB(unsigned int r, unsigned int c)
{
rows = r; columns = c;
e = new type[rows][columns];
}
~matrix_AxB()
{
delete e;
}

};


to replace all the matrices and vectors I've so far created. The difficult part will be in learning how to generalize the dot and cross products for varying dimensions.

• Do you really need varying dimensions? Usually, for 3D rendering and such, you only need 3D vectors and 4x4 homogeneous matrices... – glampert Nov 25 '14 at 19:54
• Also, GLM is a very popular 3D maths library. – glampert Nov 25 '14 at 19:55
• I just thought the AxB would cut down on code but if this all proves to be too challenging, then I may go with GLM. I'm surprised how much their code looks like mine. There's is probably way better though. – Mindril Nov 26 '14 at 6:58
• Can I make a point or polygon class that inherits from an AxB with specified dimensions? Or can they only inherit from the general form? – Mindril Nov 26 '14 at 7:00
• Varying size might promote some code reuse, but will stop you from applying several useful optimizations and will probably make the whole thing a lot more complicated. If you really plan on using variable sizes, then I would suggest making the class a template with AxB sizes as template arguments. You still have to define the size at compile time, but the code reuse is possible. – glampert Nov 26 '14 at 13:53