3D vertices class or struct - c++

I am writing a small program for learning C++ and 3D.
I have already written a vertex class with usefull methods. (like Dot,Cross, etc...)
class cVector {
...
float x, y, z;
...
float dot(cVector& v);
cVector cross(cVector& v);
...
}
Now I realize OpenGL expects buffers where elements are more like a struct (VBO).
struct sVector {
float x, y, z;
}
So my vertex class is no longer useless, because if i want to manipulate data in the buffer :
1 - I need to extract data of elements in the buffer.
2 - Create a temporary instance of vertex class with the data.
3 - Use vertex class method. (Dot, cross, etc...)
4 - Put the data back to the buffer.
It's not very efficient :(.
I wonder if I should not use a struct to organize my vectors and create global functions that take a pointer to a struct as an argument.
I could handle data buffers more efficiently (just moving pointer) but I feel i would lose the "convenient power" of C++.
In every 3D C++ source code i ever see, all use class for vertex but i dont understand how they can manipulate large amount of vertex in a "struct like" buffer.
Can you help me to understand ? What is the best approach ?

The most common approach in a language like C++ is actually neither of these things.
You are more likely to encounter the following:
struct Vector3 {
union {
struct {
float x,y,z;
};
float v [3];
};
...
Vector3 (float x_, float y_, float z_) : x (x_), y (y_), z (z_) { };
float Norm (void) { return sqrt ((x * x) + (y * y) + (z * z)); }
void Normalize (void) {
float norm = Norm ();
v [0] /= norm;
v [1] /= norm;
v [2] /= norm;
}
};
The reason for this is because using anonymous unions and structs, you can treat the data as either an array of floats (v [...]) or reference the individual components by their name (x, y, z) without a lot of muss or fuss. You get the best of both worlds by using the language more intelligently.
As for the difference between a struct and a class in this particular case, there is none from the perspective of memory representation. The only real difference between a class and a struct in C++ is the default access; struct has public access by default.
When GL needs to access the object's internal memory, you would accomplish this by passing it the pointer: Vector3::v or the individual components, depending on the particular function.
For instance:
Vector3 vec (1.0f, 2.0f, 3.0f);
---------------------------------
glVertex3fv (vec.v);
and
glVertex3f (vec.x, vec.y, vec.z);
are equivalent
On a side-note, anonymous structures are a non-standard extension to C++ but supported virtually everywhere. In the case that you have a compiler that does not support them, you may have to qualify access to x, y, and z by giving the struct a name.
struct Vector3 {
union {
struct {
float x,y,z;
} s;
float v [3];
};
};
If you write your struct this way, then:
Vector3 vec;
assert (vec.v [0] == vec.s.x);
It is messier to have to qualify x that way (using an anonymous struct you can use vec.x).

There is exactly one difference between struct and class: For class the default scope is private, while for struct it is public.
So
class cVector {
...
float x, y, z; // data
...
float dot(cVector& v); // just a function
cVector cross(cVector& v); // just a function
...
}
and
struct sVector {
float x, y, z; // data
}
have exactly the same memory layout (given that x,y,z are the only members variables of cVector).
You can use &v.x to get a pointer to (x,y,z) for OpenGL, e.g. glVertex3f(&v.x);.
You can even do the following to get a pointer to a continuous sequence of vertices for usage with OpenGL:
std::vector<cVector> vertices(100);
const float* data = &(vertices[0].x);

Related

C++ vector class definition

I'm only beginning in C++ and I'm struggling to understand some code from a custom vector class in an article I'm working through. The author writes it as:
class vec3
{
public:
vec3() {}
vec3(float e0, float e1, float e2)
{
e[0] = e0;
e[1] = e1;
e[2] = e2;
}
(...)
But so far I've only seen class definitions where the types of data it holds are defined, such as:
class vec3
{
public:
float m_x;
float m_y;
float m_z;
vec3(float x, float y, float z) : m_x(x), m_y(y), m_z(z)
{}
My guess was that the code in the article is creating an empty vector which it then populates with floats or there was something assumed in the definition. Is this just a syntax difference or is there something more fundamental that I'm missing? Apologies for what seems like a basic question but I couldn't find any similar questions. . . it might be too basic for that! But I just wanted to understand it before I moved on.
Thanks,
Paddy
In the code you've posted, you are correct that there is no declaration for the variable e anywhere. I'm not sure if this is because you didn't post that part of the code from the book, or if the book omitted that for brevity.
Without knowing what the book author was meaning by e, I don't want to suggest a completion of the code. There are several things that e could be declared as that would be compatible with the code you've posted.
It defines e as just a float array [e[3]].
With this information added, then there is no relevant difference between three separate members and an array. In the end, both variants will require the same amount of memory, and in most cases, the (optimised!) code generated by the compiler will be exactly the same:
float getY()
{
return m_y;
// will result in address of object + offset to m_y
}
float getY()
{
return e[1];
// will result in address of object + offset to e + offset to second element
// as both offsets are constant, they will be joined to one single summand
// and we are back at first variant...
}
One of the few things you can do with arrays but not with separate members is having a loop, such as the following:
float magnitude()
{
float sum = 0.0F;
for(auto f : e)
sum += f*f;
return sqrtf(sum);
}
However, for such short loops, loop unrolling is pretty likely, and the code generated again is with high probability equivalent to the separate member variant:
float magnitude()
{
return sqrtf(m_x * m_x + m_y * m_y + m_z * m_z);
}
With an array, you could pass all three members in one single parameter to other functions (as pointer to first element), with separate members, you'd have to pass all of them separately (well, there are ways around, but they either require extra effort or are "dirty"...).

What is the advantage of using union for struct and array of same size

I read somewhere a piece of code for defining 3d coordinate. So, they used x, y & z coordinate like this below:
union
{
struct
{
float x, y, z;
};
float _v[3];
};
My question is that why a union is required here and also what is the advantage of using struct with an array?
Important note: this construct leads to undefined behavior. What follows is a description of its authors' intentions, which, unfortunately, many compilers translate to precisely the behavior the authors expect, which in turn leads to proliferation of code like that.
union construct is not really required here: the authors used it for convenience. The reason they put a union there is to give themselves a syntax for accessing x, y, and z in two distinct ways:
By specifying the field name - that is, coord.x, coord.y, or coord.z, or
By specifying the field index - that is, coord._v[0], coord._v[1], or coord._v[2].
An approach that provides comparable functionality without running into undefined behavior is to use inline member functions for your access:
struct Vector3D {
int v[3];
int& x() { return v[0]; }
int& y() { return v[1]; }
int& z() { return v[2]; }
};
int main() {
Vector3D coord;
coord.v[0] = 5;
cout << coord.x() << endl;
coord.y() = 10;
cout << coord.v[1] << endl;
return 0;
}
Demo.
As Gill Bates says, in this way you can (maybe) access the 3 coordinates both as x, y, z and as v[0], v[1], v[2]
But as per #Richard Critten comment, this is actually an UB.
You can get the same result in a "safe" way with something like this:
struct Coordinates
{
Coordinates():x(v[0]), y(v[1]), z(v[2])
{
}
int v[3];
int& x;
int& y;
int& z;
};
i.e., using references to the array values and initializing them in constructor
Size of this struct will be obviously different (larger) than the union you show in OP
This way you can address the 3d coordinate as a struct..
foo.x;
foo.y; // etc
But it also allows you to get the 3 variables as an array while occupying the same space (that's the plan at least), accessing them like..
foo._v[0] // x, etc
Anyway, that's the idea. But the moment the struct has any sort of padding between members your array will be misaligned and you will end up reading garbage values. Long story short, this code has undefined behaviour, a bad implementation that shouldn't be used.

C++ Fill a vector with another vector

I have two vectors, and I would like to fill the first one with the second. The vectors are declared like this:
vector<Vec3> firstVector;
Where Vec3 is a struct with float x, y, z.
I have tried liked this with assign:
secondVector.assign(firstVector.begin(), firstVector.end());
But it stops and complains, that there is problem with the end().
I have also tried pushback, but of course it's not working.
As I read before I should do it with assign, but I don't know how to solve it properly.
EDIT:
The error message with insert and assign are the same:
this 0x00000000 ... std::vector > * const
[size] CXX0030: Error: expression cannot be evaluated
[capacity] CXX0030: Error: expression cannot be evaluated
And it points to Visual Studio's vector file to iterator end to the return. With insert it points to iterator begin.
THE CODE:
The first Vector is also part of a struct:
struct o3DModel
{
vector<Vec3> v_Vertices;
};
struct Vec3 {
public:
Vec3() {}
Vec3(float X, float Y, float Z)
{
x = X;
y = Y;
z = Z;
}
float x, y, z;
};
I declare the "o3DModel" struct above in my app class like this and send it to my loader class:
o3DModel *tfTable;
void TheApp::Init()
{
objLoader->ImportOBJ(tfTable, "testcube.obj");
}
The objLoader class, where I successfully fill my "v_Vertices" vector, where "oModel" is the sent "tfTable":
bool OBJLoader::ImportOBJ(o3DModel *oModel, char *strFileName)
{
FillObjData(oModel);
...
return true;
}
void OBJLoader::FillObjData(o3DModel *oModel)
{
oModel->v_Vertices.insert(oModel->v_Vertices.begin(), v_Vertices.begin(), v_Vertices.end());
// This here with insert
outFile2 << oModel->v_Vertices[0].x << "\n";
}
Hope this helps.
If you want secondVector to take on all of the values of firstVector and no others,
secondVector = firstVector;
If you want each of the elements of firstVector to be added to the end secondVector:
secondVector.insert(secondVector.end(),
firstvector.begin(), firstVector.end());
If you want each of the elements of firstVector to be added to the beginning of secondVector:
secondVector.insert(secondVector.begin(),
firstVector.begin(), firstVector.end());
Or if you don't want to do it in the ctor use
secondVector = firstVector
This should work:
vector<Vec3> secondVector(firstVector.begin(), firstVector.end());
That's the case when you're interested in using the vector constructor.
You second vector needs to be declared as a vector of vectors of Vec3 strucs.
vector<vector<Vec3>> secondVector;
secondVector.push_back(firstVector);
Okay, I have solved it, but with a little roundabout. In FillObjData I have created a new Vec3, created an if, gived the first vector x, y, z coordinate to the new Vec3, and pushed the Vec3 into the vector. And when I declared my struct I have declared it real not as a pointer. Now it works perfectly.

How to differentiate two constructors with the same parameters?

Suppose we want two constructors for a class representing complex numbers:
Complex (double re, double img) // construct from cartesian coordinates
Complex (double A, double w) // construct from polar coordinates
but the parameters (number and type) are the same: what is the more elegant way
to identify what is intended? Adding a third parameter to one of the constructors?
It is better to add static methods with appropriate names and let them to create the objects.
static Complex createFromCartesian(double re, double img);
static Complex createFromPolar(double A, double w);
You can't have two constructors (or any functions) with the same signatures. The best solution is probably to create classes for your coordinate types and overload on those. For example:
struct CartCoord {
CartCoord( double re, double img ) : mRe(re), mImg(img) {}
double mRe, mImg;
};
struct PolarCoord {
PolarCoord( double a, double v ) : mA(a), mV(v) {}
double mA, mV;
};
Then your constructors become:
Complex( const CartCoord & c );
Complex( const PolarCoord & c);
In use:
Complex c( CartCoord( 1, 2 ) );
You can also use them with overloaded operators of the Complex class. For example, assuming you have a binary + operator for the class define as:
Complex operator+( const Complex &, const Complex & );
then:
Complex a( CartCoord( 0, 0 ) );
Complex b = a + PolarCoord( 1, 1 );
As we have a conversion constructor from PolarCoord to Complex, this will be used in the + expression. This is more natural (IMHO) than calling static functions to create the temporary..
This is an example of Koenig's dictum (or at least a version of it) - whenever faced with a difficult problem, introduce a new level of classes to solve it.
Use the named constructor idiom described here at the Parashift C++ FAQ.
You can't - if the method signatures are the same, you're stuffed.
Of course, you could always create a subclass for each type of coordinate system, but that's far from ideal - especially if you later find a good reason to want to subclass Complex for other reasons...
Instead of having two constructors, you need to have only one, but add a third parameter, for example:
Complex (double re, double img, enum type) {
if(type == polar) {
..treat as polar coordinates..
} else {
..treat as cartesian coordinates..
}
}
'enum type' can have a default type as well so you don't have to supply what type of coordinates you intend to use every time, the default should off course be what's most used.
Complex (double re, double img, enum type = polar);
Since no one mentioned it, you can use tags:
class Complex{
struct CartCoord{};
struct PolarCoord{};
Complex( CartCoord, double re, double img);
Complex( PolarCoord, double a, double v);
};
int main(){
auto c1 = Complex(Complex::CartCoord{}, 5, 6);
auto c2 = Complex(Complex::PolarCoord{}, 5, 6);
}
I don't know if it is good practice in C++ but I would name these two methods differently, at least for a maintainability point of view.
I would probably create more classes, but then I am an adept of Boost Strong Typedef library.
For me it does not make sense to use double to represent both coordinates, module and angles.
So I would have:
class CoordinateX {};
class CoordinateY {};
class Modulus {};
class Angle {};
class Complex
{
public:
Complex(CoordinateX, CoordinateY);
Complex(Modulus, Angle);
};
And there it's perfectly clear, and there is no ambiguity. Also you add some compile-time check of "units" in a loose sense. It rarely makes sense (if ever) to add an X-coordinate and an Y-coordinate, or worse a distance and an angle.
For me the more elegant way would be to create a class representing cartesian coordinates and another representing polar coordinates, then give object of the relevant class to the constructors.
That way you would have two constructor using different parameters.
I use this simple alternative way while practicing C++, I don't know if it is what you want.
class Vector{
public:
float x, y;
Vector();
Vector(float , float, bool);
float get_distance(Vector v); // find distance from another vector
float get_magnitude(); // find distance from origin point
Vector add(Vector v);
Vector subtract(Vector v);
Vector multiply(Vector v); // multiply by vector
Vector multiply(float scalar); // multiply by scalar
float get_angle();
};
Vector::Vector(float a, float b, bool is_cartesian = true){
if(is_cartesian){
x = a;
y = b;
}
else{
x = a * cos( b );
y = a * sin( b );
}
}

C++ member variable aliases?

I'm pretty sure this is possible, because I'm pretty sure I've seen it done. I think it is awesome, but I will gladly accept answers along the lines of "this is a terrible idea because ____".
Say we have a basic struct.
struct vertex
{
float x, y, z;
};
Now, I want to implement aliases on these variables.
vertex pos;
vertex col;
vertex arr;
pos.x = 0.0f; pos.y = 0.5f; pos.z = 1.0f;
col.r = 0.0f; col.g = 0.5f; col.b = 1.0f;
arr[0] = 0.0f; arr[1] = 0.5f; arr[2] = 1.0f;
Ideally the third syntax would be indistinguishable from an array. That is, if I sent arr as a reference parameter to a function expecting an array of floats into which it will store data (eg many of the OpenGL glGet functions), it would work fine.
What do you think? Possible? Possible but stupid?
What I would do is make accessors:
struct Vertex {
float& r() { return values[0]; }
float& g() { return values[1]; }
float& b() { return values[2]; }
float& x() { return values[0]; }
float& y() { return values[1]; }
float& z() { return values[2]; }
float operator [] (unsigned i) const { return this->values_[i]; }
float& operator [] (unsigned i) { return this->values_[i]; }
operator float*() const { return this->values_; }
private:
float[3] values_;
}
Nameless nested structs in a union are not standard C++. This, however, should work:
struct Vertex
{
private:
typedef float Vertex::* const vert[3];
static const vert v;
public:
typedef size_t size_type;
float x, y, z;
const float& operator[](size_type i) const {
return this->*v[i];
}
float& operator[](size_type i) {
return this->*v[i];
}
};
const Vertex::vert Vertex::v = {&Vertex::x, &Vertex::y, &Vertex::z};
EDIT: A little more information. The struct uses an array of 3 pointer-to-data-members to access the data in the overloaded [] operators.
The line "typedef float Vertex::* const vert" means that vert is a pointer to a float member of the Vertex struct. The [3] means that it's an array of 3 of these. In the overloaded operator[], this array is indexed and the pointer-to-data-member is dereferenced and the value returned.
Additionally, this method should work regardless of packing issues - the compiler is free to pad the Vertex structure however it likes and it'll still work just fine. An anonymous union will run into problems if the floats are packed differently.
Use a union?
union vertex
{
struct { float x, y, z; };
struct { float r, g, b; };
float arr[3];
};
I wouldn't recommend it - it will lead to confusion.
Added:
As noted by Adrian in his answer, this union with anonymous struct members is not supported by ISO C++. It works in GNU G++ (with complaints about not being supported when you turn on '-Wall -ansi -pedantic'). It is reminiscent of the pre-pre-standard C days (pre-K&R 1st Edn), when structure element names had to be unique across all structures, and you could use contracted notations to get to an offset within the structure, and you could use member names from other structure types - a form of anarchy. By the time I started using C (a long time ago, but post-K&R1), that was already historical usage.
The notation shown with anonymous union members (for the two structures) is supported by C11 (ISO/IEC 9899:2011), but not by earlier versions of the C standard. Section 9.5 of ISO/IEC 14882:2011 (C++11) provides for anonymous unions, but GNU g++ (4.9.1) does not accept the code shown with -pedantic, identifying "warning: ISO C++ prohibits anonymous structs [-Wpedantic]".
Since the idea will lead to confusion, I'm not particularly concerned that it isn't standard; I would not use the mechanism for this task (and I'd be leery of using anonymous structures in a union even if it was beneficial).
A concern was raised:
The three (x-y-z, r-g-b and the array) do not necessarily align.
It is a union with three elements; the three elements start at the same address. The first two are structures containing 3 float values. There's no inheritance and there are no virtual functions to give different layouts, etc. The structures will be laid out with the three elements contiguous (in practice, even if the standard permits padding). The array also starts at the same address, and subject to 'no padding' in the structures, the elements overlap the two structures. I really don't see that there would be a problem.
References?
template<typename T>
struct vertex {
vertex() :
r(data[0]), g(data[1]), b(data[2]),
x(data[0]), y(data[1]), z(data[2])
{
}
T *operator *() {
return data;
}
const T *operator *() const {
return data;
}
T data[3];
T &r, &g, &b;
T &x, &y, &z;
};
You can get this with a union as others have mentioned. Overloading color and position onto the same structure like this may not be a good idea ( for example, adding two colors usually means you want to saturate to 1.0, whereas adding vectors happens linearly ), but overlaying a float[] on top of them like that is perfectly fine and a well accepted means of interchanging data with GL/DirectX/etc.
I recommend you avoid referring to the same member by different aliases in the same function scope, though, because this will drive you into a nasty hardware stall called a load-hit-store. In particular, avoid this if you can:
vector foo;
foo.x = 1.0f;
return foo[0] + foo[1];
Following structure will have the requested behavior:
struct vertex
{
private:
float data[3];
public:
float &x, &y, &z;
float &r, &g, &b;
vertex() : x(data[0]), y(data[1]), z(data[2]), r(data[0]), g(data[1]), b(data[2]) {
}
float& operator [](int i) {
return data[i];
}
};
I guess you can do some macro magic to get what you want.
But that will look ugly. Why do you want to use same struct, vertex for 3 different types? Why can't you define class for color?
Also keep in mind that vertex and color are not same. If you change something to vertex, that will affect the color also, if you have the same class for both.
I am not sure whether I understood the question correctly. But it looks like you need to overload the operator[] to provide array like access to your struct/class. See the example mentioned here: Operator overloading
I have a template and two Vector classes below, one crazy, one sane. The template implements a simple fixed at compile time array of values. It is designed for subclassing and uses a protected array variable to avoid you having to jump through hoops to access the array. (Some folks might not like such a design. I say, if your subclasses are calling your overloaded operators, coupling might be a good idea.)
The crazy class allows you to have member variables called x, y, z and it acts like an array for calls to glGetFloatV. The sane one just has accessor functions x(), y(), z() and still works with glGetFloatV. You can use either class as a basis for other vector objects you might pass to the OpenGL library. Although the classes below are specific to points, you can obviously just do a search/replace to turn them into a rgb color classes.
The crazy class is crazy because the cost of the syntactic sugar vec.x instead of vec.x() is 3 reference variables. That could take up a lot of space in a large application. Use the simpler sane version.
template <typename T, int N>
class FixedVector {
protected:
T arr[N];
public:
FixedVector();
FixedVector(const T* a) {
for (int i = 0; i < N; ++i) {
arr[i] = a[i];
}
}
FixedVector(const T& other) {
for (int i = 0; i < N; ++i) {
arr[i] = other.arr[i];
}
}
FixedVector& operator=(const T& other) {
for (int i = 0; i < N; ++i) {
arr[i] = other.arr[i];
}
return *this;
}
T* operator&() { return arr; }
const T* operator&() const { return arr; }
T& operator[](int ofs) {
assert(ofs >= 0 && ofs < N);
return arr[ofs];
}
const T& operator[](int ofs) const {
assert(ofs >= 0 && ofs < N);
return arr[ofs];
}
};
class CrazyPoint : public FixedVector<float, 3> {
public:
float &x, &y, &z;
CrazyPoint()
: x(arr[0]), y(arr[1]), z(arr[2])
{ arr[0] = arr[1] = arr[2] = 0.0; }
CrazyPoint(const float* a)
: x(arr[0]), y(arr[1]), z(arr[2])
{
arr[0] = a[0];
arr[1] = a[1];
arr[2] = a[2];
}
CrazyPoint(float a, float b, float c)
: x(a), y(b), z(c)
{
arr[0] = a;
arr[1] = b;
arr[2] = c;
}
};
class SanePoint : public FixedVector<float, 3> {
public:
float& x() { return arr[0]; }
float& y() { return arr[1]; }
float& z() { return arr[2]; }
SanePoint() { arr[0] = arr[1] = arr[2] = 0.0; }
SanePoint(float a, float b, float c)
{
arr[0] = a;
arr[1] = b;
arr[2] = c;
}
};
// usage
SanePoint normal;
glGetFloatV(GL_CURRENT_NORMAL, &normal);
Bad idea in my opinion, at least for the example given: the downside is that, for just about any solution to this, you're probably going to be able to freely assign "rgb" instances to/from "xyz" instances, which is probably rarely sensible or correct. ie you risk giving up some useful type safety.
Personally, for the example you give, I'd subclass rgb and xyz types from a base boost::array<float,3> or similar. So both of them inherit operator[], can be passed to functions expecting arrays, and passed with more type safety to things expecting colours/coordinates. It's often you want to treat an xyz or an rgb as an array, but rare you want to treat an xyz as an rgb or vice-versa. (rgb IS-A array: OK. xyz IS-A array: OK. rgb IS-A xyz ???? I don't think so!)
Of course that means access to x,y,z & r,g,b needs to be by accessor (forwarding to the appropriate operator[](...) ) rather than direct to the member. (You'd need C#'s properties for that).
You can try adding references to variables, like this:
struct test {
float x, y, z;
float &r, &g, &b;
test() : r(x), g(y), b(z) {}
};
But your structure gets bigger (from 12 bytes to 40 bytes).
To use [] on it, use overloading of operator[], as mentioned before.
Just a warning about using reference members pointing to value members. You need to define a copy constructor (and possibly also assignment operator), if you ever copy such an object (like transfer it by value). The default copy constructor will leave you with a copy whose reference members point to the value members of the original object, not the ones of the new object. This is certainly not something you want.
Considering you also end up with larger objects, as already pointed out, I think using accessor methods is to be preferred over reference members.
I think the poster was looking for something very simple, with no performance overhead - as you would want with something like a 3D vector class. So adding virtual functions (vtable indirection cost), additional members (memory cost), unions (each new name may require a recompile of all users), or even preprocessor magic (increased program size, cross-type equivalency) is undesirable.
Real world use case would be to take a templated Vector3 class (which could be double-based or float-based) and apply it to other scenarios in a user-friendly manner. It is likely defined with [x, y, z] members, but if you want to use it for rotations, you might want [psi, theta, phi], for speeds [dx, dy, dz], etc.
For the entire type, you can use the following to alias it at compile time:
using Rotation3 = Vector3;
But there appears to be nothing as simple or performant that you can do for aliasing the underlying variables, right?