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[3];

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

    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[0] = e[1] * vec.e[2] - e[2] * vec.e[1];
        out.e[1] = e[0] * vec.e[2] - e[2] * vec.e[0];
        out.e[2] = e[0] * vec.e[1] - e[1] * vec.e[0];

        return out;
    }

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

    vector3()
    {
        e[0] = e[1] = e[2] = 0;
    }
    ~vector3(){}
}; typedef vector3 v3_;

This is the 3 by 3 matrix:

struct matrix_3x3
{
    double e[3][3];

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

    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[4]; 

        int count;

        _xyCount(3,3)

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



        _xy

        out.e[0][0] = (int)temp[0]; out.e[0][1] = (int)temp[1];
        out.e[1][1] = (int)temp[2]; out.e[1][1] = (int)temp[3];

    }

    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[0][0] = ax; e[1][0] = ay; e[2][0] = az;
        e[0][1] = bx; e[1][1] = by; e[2][1] = bz;
        e[0][2] = cx; e[1][2] = cy; e[2][2] = 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[0];
    }

    double y()
    {
        return e[1];
    }

    double z()
    {
        return e[2];
    }

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

    void x(double n)
    {
        e[0] = n;
    }

    void y(double n)
    {
        e[1] = n;
    }

    void z(double n)
    {
        e[2] = n;
    }

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

    void xyz(double X, double Y, double Z)
    {
        e[0] = X; e[1] = Y; e[2] = Z;
    }

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

    double abs()
    {
        return cSqrt(_sq(e[0]) + _sq(e[1]) + _sq(e[2]));
    }

    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[0]); y(v.e[1]); z(v.e[2]);
    }

    point3 operator+(point3 p)
    {
        point3 out;
        out.e[0] = e[0] + p.e[0]; 
        out.e[1] = e[1] + p.e[1]; 
        out.e[2] = e[2] + p.e[2];
        return out;
    }

    point3 operator-(point3 p)
    {
        point3 out;
        out.e[0] = e[0] - p.e[0]; 
        out.e[1] = e[1] - p.e[1]; 
        out.e[2] = e[2] - p.e[2]; 
        return out;
    }

    point3 operator/(double d)
    {
        point3 out;
        out.e[0] = e[0] / d; 
        out.e[1] = e[1] / d; 
        out.e[2] = e[2] / d;
        return out;
    }

    point3 operator*(double d)
    {
        point3 out;
        out.e[0] = e[0] * d; 
        out.e[1] = e[1] * d; 
        out.e[2] = e[2] * 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[0] = e[1] * p.e[2] - e[2] * p.e[1];
        out.e[1] = e[0] * p.e[2] - e[2] * p.e[0];
        out.e[2] = e[0] * p.e[1] - e[1] * p.e[0];

        return out;
    }

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

    point3(double a, double b, double c)
    {
        e[0] = a; e[1] = b; e[2] = c;
    }

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

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

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

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

    p3_ A()
    {
        p3_ out;
        out.x(e[0][0]); out.y(e[1][0]); out.z(e[2][0]);
        return out;
    }

    p3_ B()
    {
        p3_ out;
        out.x(e[1][0]); out.y(e[1][0]); out.z(e[2][1]);
        return out;
    }

    void A(p3_ a)
    {
        e[0][0] = a.x(); e[1][0] = a.y(); e[2][0] = a.z();
    }

    void B(p3_ a)
    {
        e[0][1] = a.x(); e[1][1] = a.y(); e[2][1] = 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][0];             
        }
        return out;
    }

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

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

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

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

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

    void C(p3_ in)
    {
        _count(3)
        {
            e[count][2] = 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[2];

        _count(3)
        {

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

        }

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

        double dp = temp[0] * temp[1];
        double absB = temp[0].abs();
        double absC = temp[0].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[0][count];
            Y += e[1][count];
            Z += e[2][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++;
            }
        }

        if (added)
        {
            out = P(v) + ((others[0] - P(v)) % (others[1] - P(v)));
        }
        else
        {
            out = (others[0] - P(v)) % (others[1] - 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

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.