Sign in to follow this  

x y z or float p[3]

This topic is 4332 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Which one is better for a vector class?? I'm currently using something like
class Vector_3
{
     float x,y,z;
};
But sometimes u need an array of 3 or 4 floats for opengl calls like light colors positions etc. How do you handle this?Make it a float array?Or is there another way? I overloaded the [] operator this way
const float &operator[](int i)
{
if(i==0)
return x;
else if(i==1)
return y;
else if(i==2)
return z;

}
But I dont think its a good way O_O

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
look into unions, so you can have both.

class Vector3
{
union
{
struct
{
float x, y, z;
};
float p[3];
};
};

Share this post


Link to post
Share on other sites
What you can do is this:


class Vector4
{
float x, y, z, w;
float &operator[]( int i ) const
{
return ( float & )*( &x + i );
}

operator float *()
{
return &x;
}
};



This allows you to access the members using dot operators ( theVec.x ), arrays ( theVec[2] ) AND typecast it to a float pointer.

Share this post


Link to post
Share on other sites
Doh yea unions.
Well unions share the same memory as far as i know.So Im not wasting any memory for it its the same as 3 floats?
And whats the purpose of the struct inside the class cant i just have :

class Vec3
{
public:
union{
float x,y,z;
float p[3];
};
};

This seems to work.

Share this post


Link to post
Share on other sites
The problem with a union is that you have to access members using something like:

theVec.p[1]

Instead of:

theVec[1]

I suppose its down to preference, but I would recommend the operator overloads above the union solution.

Edit: You can also do this:

glFunction( theVec )

No '&' symbol.

Share this post


Link to post
Share on other sites
Quote:
Original post by TheOddMan
What you can do is this:

*** Source Snippet Removed ***

This allows you to access the members using dot operators ( theVec.x ), arrays ( theVec[2] ) AND typecast it to a float pointer.


Watch out, this is only legal for POD types. If your x,y,z are private, have constructors, or whatever else, then it's not legal. For a discussion of an always-legal solution, see here.

Share this post


Link to post
Share on other sites
You can make the solution use private data types easily:


class Vector3
{
private:
float x, y, z;
public:
float &X() { return x; }
const float &X() const { return x; }

float &Y() { return y; }
const float &Y() const { return y; }

float &Z() { return z; }
const float &Z() const { return z; }

float &operator[]( int i ) const
{
return ( float & )*( &x + i );
}

operator float *()
{
return &x;
}
};




Just altered in my project and seems fine.

Share this post


Link to post
Share on other sites
another problem when overloading [] is when I have a array of vectors lets say

Vector_3 *pVertices = new Vector_3[1000];

not If i want to reach the 500 vertex

pVertices[500] but this will call the overloaded [] right??What will happen?

Share this post


Link to post
Share on other sites
Not really. I've had them public in my classes, Microsoft has them public in their classes so it must be alright. Then again it does break the law of encapsulation, so Object-Oriented purists would say the data members *have* to be private.

I'd say its down to coding style, I think the public data members are more elegant ( theVec.x instead of theVec.X() ), and it's unlikely a vector class would ever change after its completed. Then again if it were to change...

Share this post


Link to post
Share on other sites
Quote:
Original post by Black Knight
another problem when overloading [] is when I have a array of vectors lets say

Vector_3 *pVertices = new Vector_3[1000];

not If i want to reach the 500 vertex

pVertices[500] but this will call the overloaded [] right??What will happen?


No, it would call the array as normal. To call the overload you would do something like:

Vector_3 *pVertices = new Vector_3[1000];

pVertices[500][0] = 2.30f;

The array acts like a 2d array, the [500] references the vector to edit, the [0] references the x in the 500th vector. You could also do this:

pVertices[500].x = 2.30f;
pVertices[500] = Vector_3( 2.30f, 0.00f, 1.00f );

Assuming a constructor existed that took 3 floats.

Share this post


Link to post
Share on other sites
wrt to union vs operator, I personally prefer to take the best of both worlds
class Vector_3
{
public:
union
{
struct
{
float x, y, z;
};
float p[3];
};
float&operator [](int index)
{
return p[index];
}
};

Quote:
Original post by Black Knight
Doh yea unions.
Well unions share the same memory as far as i know.So Im not wasting any memory for it its the same as 3 floats?
And whats the purpose of the struct inside the class cant i just have :

class Vec3
{
public:
union{
float x,y,z;
float p[3];
};
};

This seems to work.


The inner-struct is there to prevent the union from making x, y and z a single variable. Without it, x=y=z=p[0], which isn't what you want.

Share this post


Link to post
Share on other sites
I tried to make some template funcs then i removed them but I get errors now like this
C:\Program Files\Microsoft Visual Studio 8\VC\include\xutility(572) : error C2039: 'iterator_category' : is not a member of 'Vector_4'
d:\st projects (source)\stlibs\stengine\math\Vector.h(128) : see declaration of 'Vector_4'
.\Drawable.cpp(142) : see reference to class template instantiation 'std::iterator_traits<_Iter>' being compiled
with
[
_Iter=Vector_4
]

I dunno how to fix them.Any idea?

Share this post


Link to post
Share on other sites
Quote:
Original post by TheOddMan
I'd say its down to coding style, I think the public data members are more elegant ( theVec.x instead of theVec.X() ), and it's unlikely a vector class would ever change after its completed. Then again if it were to change...


My view is that 'theVec.X()' generally (a) adds extra useless complexity and (b) is effectively lying. Real classes can perform more useful things, anyway. This sort of function is just adding a useless 'hook' for invariant-maintaining code and then (in practice) never filling it in.

Share this post


Link to post
Share on other sites
Ok another useless question :)
lets say i have this

Vector_3 normalize(const Vector_3 *pNormal)
{
float mag = pNormal->magnitude();
Vector_3 vNormal = Vector_3(pNormal->x / mag,pNormal->y / mag,pNormal->z / mag);
return vNormal;
}


Now what happens if I call it from my app like this??

vector3 = normalize(&(vector1 - vector2));

It does not give a compile error but what address does it send to the function??
Sorry for the Qs :]


Share this post


Link to post
Share on other sites
Don't do that, is the short answer. Instead, make them friend functions, and pass by reference:


class Vector3
{
// friend functions can access the members of the classes they're
// declared as friends in
inline friend float Magnitude(const Vector3& v)
{
return sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}

inline friend Vector3 Normalize(const Vector3& v)
{
float m = Magnitude(v);
return v / m;
}

// likewise for CrossProduct:
inline friend Vector3 CrossProduct(const Vector3& lhs, const Vector3& rhs)
{
return Vector3( lhs.y * rhs.z - lhs.z * rhs.y,
lhs.z * rhs.x - lhs.x * rhs.z,
lhs.x * rhs.y - lhs.y * rhs.x );
}
};


Edit: I should probably mention that you use them like ordinary functions (well, they are ordinary functions, just with special permissions, really). Like so:


int main()
{
Vector3 v = CrossProduct(v1, v2);
}
You don't have to do any Vector3::CrossProduct(...) stuff at all. Easy.

Share this post


Link to post
Share on other sites
When you call (vector1 - vector2) a temporary instance of class Vector_3 is created, and the function gets the address of this temporary. Now passing the address of a temporary is not the best idea, as you might imagine...

Share this post


Link to post
Share on other sites
Well I have something like this now.
I will use it for colors too so I added the r,g,b,a too.


//Vector 4 Class
class Vector_4
{
public:
union
{
struct
{
float x,y,z,w;
};
struct
{
float r,g,b,a;
};
float v[4];
};

Vector_4(){x = 0.0f; y = 0.0f; z = 0.0f; w = 1.0f;};
Vector_4(float ix,float iy,float iz,float iw = 1.0f){x = ix; y = iy; z = iz; w = iw;};
Vector_4(tVertex v) {x = v.x; y = v.y; z = v.z; w = 1.0f;};

Vector_3 vec3() const
{
Vector_3 v(x,y,z);
return v;
}
float magnitude() const
{
return (float)sqrt((x*x) + (y*y) + (z*z));
}
float &operator [](int index)
{
return v[index];
}
Vector_4 operator=(const Vector_4& vec)
{
return Vector_4(x = vec.x, y = vec.y, z = vec.z,w = vec.w);
}
Vector_4 operator=(const Vector_3& vec)
{
return Vector_4(x = vec.x, y = vec.y, z = vec.z,w = 1.0f);
}
Vector_4 operator+(Vector_4 vector)const
{
return Vector_4(vector.x + x,vector.y + y,vector.z + z,vector.w + w);
}
Vector_4 operator-(Vector_4 vector)const
{
return Vector_4(x - vector.x, y - vector.y, z - vector.z);
}
Vector_4 operator+(float num)
{
return Vector_4(x + num,y + num,z + num);
}
Vector_4 operator*(float num)
{
return Vector_4(x * num,y * num,z * num);
}
Vector_4 operator/(float num) const
{
return Vector_4(x / num,y / num,z / num);
}
const Vector_4& operator+=(const Vector_4& vec)
{
x += vec.x;
y += vec.y;
z += vec.z;
w += vec.w;
return *this;
}
const Vector_4& operator+=(const Vector_3& vec)
{
x += vec.x;
y += vec.y;
z += vec.z;
return *this;
}
const Vector_4& operator-=(const Vector_4& vec)
{
x -= vec.x;
y -= vec.y;
z -= vec.z;
return *this;

}
const Vector_4 &operator*=(const float &s)
{
x *= s;
y *= s;
z *= s;

return *this;
}

const Vector_4 &operator*=(const Vector_4& vec)
{
x *= vec.x;
y *= vec.y;
z *= vec.z;
return *this;
}

const Vector_4 &operator/=(const float &s)
{
const float recip = 1/s;

x *= recip;
y *= recip;
z *= recip;

return *this;
}
const Vector_4 &operator+=(const float s)
{
x += s;
y += s;
z += s;
return *this;
}
const bool operator!=(const Vector_4& vec)
{
if( x != vec.x&&
y != vec.y&&
z != vec.z)
return true;
else return false;

}
const Vector_4 operator*(const float &s) const
{
return Vector_4(x*s, y*s, z*s);
}

friend const Vector_4 operator*(const float &s, const Vector_4 &vec)
{
return vec*s;
}
};



Share this post


Link to post
Share on other sites
Quote:
Original post by Black Knight
Doh yea unions.
Well unions share the same memory as far as i know.So Im not wasting any memory for it its the same as 3 floats?
And whats the purpose of the struct inside the class cant i just have :

class Vec3
{
public:
union{
float x,y,z;
float p[3];
};
};

This seems to work.


No. This means x, y, z and p[0] will all share the same memory, while only p[1] and p[2] will work as intended. This is why the struct is needed.

[code]
class Vector3
{
public:

union
{
struct { float x, y, z; };
float p[3];
};
};

Share this post


Link to post
Share on other sites
Hey its me again :D
After changing the my base object class' position from Vector_3 to Vector_4 I had lots of errors cuz lots of functions were taking the position as a parameter with type Vector_3.
So I added this to my Vector_4 class.

class Vector_4
{
public:
union
{
struct
{
Vector_3 vec3;
float w;
};
struct
{
float x,y,z,w;
};
struct
{
float x,y,z,iBoneID;
};
struct
{
float r,g,b,a;
};

float v[4];
};

};


And lets say I have a base object like this:


class STObject
{
protected:
Vector_4 m_vPosition;

public:
const Vector_4 &getPosition(){return m_vPosition;};

}



Now I call functions like this:

findIntersection(pTerrain,pObject->getPosition().vec3);

And lots of other functions are doing the same.What else can I do?
I dont want to overload each function like
float dot(Vector_3 v1,Vector_3 v2)
float dot(Vector_4 v1,Vector_4 v2)

I thought I may use templates but sometimes I need to take the dot of a Vector_3 and a Vector_4 O_O.
Ok enought for now :=)


Share this post


Link to post
Share on other sites
Quote:
Original post by Black Knight
but sometimes I need to take the dot of a Vector_3 and a Vector_4 O_O.


Um? A dot product is normally only meaningful between vectors of the same length. What kind of math are *you* doing o_O

Share this post


Link to post
Share on other sites

This topic is 4332 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this