Convert class to fixed-length float array - c++

How can I convert the following class to a fixed-length float array?
class Vertex
{
public:
Vertex( float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
float x, y, z;
};
For example, I would like to use it like so:
Vertex v(0, 1, 0);
float arr[3] = v; // How to convert here?
Thanks!
Edit:
I should have added some background information before posting this question.
The reason why I'm using C-style arrays is because I want to combine the high level vertex objects into a vertex array for rendering with OpenGL, which as far as I know requires a collection of raw arrays (float[3]) or structs.
For that purpose I think user2079303's answer is the best option. However, if a more elegant solution exists that would be even better. :)

#include <iostream>
#include <array>
using namespace std;
class Vertex
{
public:
Vertex( float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
operator array<float, 3>() const {
return {x,y,z};
}
/* See #user2079303's answer for a compile-time check of the array dimension */
void fillArray(float arr[3]) {
arr[0] = x;
arr[1] = y;
arr[2] = z;
}
float x, y, z;
};
int main() {
Vertex v(1,1.4,2);
array<float, 3> arr = v;
float arr2[3];
v.fillArray(arr2);
for (int i = 0; i < 3; i++) {
cout << arr[i] << " " << arr2[i] << endl;
}
return 0;
}
Live Demo
std::array is as efficient as using a C-style array, no performance is lost. You can also use std::vector instead.
You can't just return and copy an array, even in C. That's why if you absolutely want to use a C array, you have to have a function like fillArray.

A class cannot be convertible to a (raw) array, because the cast operator would have to return an array, which is not allowed in c++. Furthermore, arrays cannot be copy-initialized anyway.
What you can do is define an array, and pass it to a function that populates the array according to the contents of an object:
void Vertex::fill_arr(float (&arr)[3]) {
arr[0] = x;
arr[1] = y;
arr[2] = z;
}
// usage
Vertex v(1, 2, 3);
float arr[3];
v.fill_arr(arr);
Another option is to use std::array which can be returned and copy-initialized normally.

You have many options, and it which you choose depends a lot on context. Here are four different ways to "convert" your vertex:
class Vertex
{
public:
Vertex(float x = 0,
float y = 0,
float z = 0)
: x(x), y(y), z(z) {}
operator array<float, 3> () const {
return {x, y, z};
}
array<float, 3> array_copy() const {
return {x, y, z};
}
unique_ptr<float[]> c_array_copy() const {
return unique_ptr<float[]>(new float[3]{ x, y, z });
}
void copy_into(float in[3]) const {
in[0] = x;
in[1] = y;
in[2] = z;
}
float x, y, z;
};
First, you can just cast the class using the () operator:
cout << "Direct access" << endl;
auto as_array = (array<float, 3>)vertex;
cout << as_array[0] << as_array[1] << as_array[2] << endl;
Second, you can let copy semantics to some work for you with array_copy():
cout << "Get a copy" << endl;
auto as_copy = vertex.array_copy();
cout << as_copy[0] << as_copy[1] << as_copy[2] << endl;
Third, you can get a more c-style array copy with a unique pointer to a dynamically allocated array:
cout << "Get a c-style copy" << endl;
auto as_c_copy = vertex.c_array_copy();
cout << as_c_copy[0] << as_c_copy[1] << as_c_copy[2] << endl;
Finally, you can copy into an out-parameter:
cout << "Copy onto an out-parameter" << endl;
float copied[3];
vertex.copy_into(copied);
cout << copied[0] << copied[1] << copied[2] << endl;
As I say, which you choose really depends on context and performance requirements.
Note that in no case can you just return a c-style array.

You can define a conversion operator to construct your array. Also I would suggest using a std::array instead of a raw array.
#include <array>
class Vertex
{
public:
Vertex(float x = 0.0f, float y = 0.0f, float z = 0.0f)
: x(x), y(y), z(z)
{}
float x;
float y;
float z;
operator const std::array<float, 3>() const
{
return {x, y, z};
}
};
int main()
{
Vertex v(0.0f, 1.0f, 0.0f);
std::array<float, 3> arr = v;
}

Related

fixed-size array for operators in c++

I've been this trying for several hours now. I cannot find a way to pass a fixed-size array to an operator. I found some stuff here on stackoverflow and tried it that way, as you can see in my code, but it won't work at all. The task is, that the code shouldn't be compiled if the array is not of size 3, that means, that if the array is of size 2 or size 4, that I should get a compile error. Can someone tell me how to implement this? Thanks in advance! :)
class Vec3 {
private:
int x, y, z;
public:
Vec3 (int x, int y, int z) : x(x), y(y), z(z) {}
int getX () const
{
return x;
}
int getY () const
{
return y;
}
int getZ () const
{
return z;
}
};
Vec3 operator+(Vec3 &vec, int (*arr)[3]) {
int x,y,z;
x = vec.getX() + (*arr)[0];
y = vec.getY() + (*arr)[1];
z = vec.getZ() + (*arr)[2];
Vec3 result(x,y,z);
return result;
}
int main () {
Vec3 v1 (1,2,3);
int v3 [] = {2,4,6};
cout << "v1 + v3 = " << v1 + v3 << endl;
return 0;
}
You got the syntax slightly wrong. Instead of
Vec3 operator+(Vec3 &vec, int (*arr)[3])
it must be
Vec3 operator+(Vec3 &vec, int (&arr)[3])
to pass the array by reference. And you can drop the value-of-operator (*) before the array-access, so you end up with
Vec3 operator+(Vec3 &vec, int (&arr)[3]) {
int x,y,z;
x = vec.getX() + arr[0];
y = vec.getY() + arr[1];
z = vec.getZ() + arr[2];
Vec3 result(x,y,z);
return result;
}
Use template to do it:
template<size_t N>
Vec3 operator+(Vec3 &vec, int (&arr)[N]) {
static_assert(N==3,"wrong size of array");
// the rest of the code , small fix: arr[0] etc
static assert will be triggered when N is not equal to 3.
Demo

Rotation of points about an axis

currently struggling with a project for my computing class in c++. Being asked to rotate a point in 3d space by 3 angles relative to the 3 axis.
feel like im kinda close on having all the parts needed just struggling to put them together, lecture notes were a bit vague on multiplying matrices :( . any help is appreciated.
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
std::cout << "Enter a number for x";
int x;
std::cin >> x;
std::cout << "Enter a number for y";
int y;
std::cin >> y;
std::cout << "Enter a number for z";
int z;
std::cin >> z;
std::cout << "Enter value for Theta";
int theta;
std::cin >> theta;
std::cout << "Enter value for Beta";
int beta;
std::cin >> beta;
std::cout << "Enter value for Gamma";
int gamma;
std::cin >> gamma;
//function allows the insertion of xyz and the three angles
{void RTheta(const double& theta, double array[3][3]);
int array =
{
{cos(theta), sin(theta), 0}, //the matrice for theta values
{sin(theta), cos(theta), 0},
{0,0,1}
};
std::cout << RTheta; //outputs value for theta
}
{
void RBeta(const double& beta, double array[3][3]);
int array =
{
{cos(beta), 0, -sin(beta)}, //the matrice for beta values
{0, 1, 0}, //outputs values for beta
{sin(beta), 0, cos(beta)}
};
std::cout << RBeta;
}
{
void RGamma(const double& gamma, double array[3][3]);
int array =
{
{1,0,0}, //the matrice for gamma
{0,cos(gamma), sin(gamma)}, //outputs values for gamma
{0, -sin(gamma), cos(gamma)}
};
std::cout << RGamma;
}
return 0;
}
the question if this helps: i.imgur.com/eN5RqEe.png
You need to start thinking from an abstraction point of view and not get lost in the details. You need the abstractions Point and Transform and create functions that work with those abstractions.
If you are working with 2D points, use:
struct Point
{
double x;
double y;
};
If you need to work with 3D points, use:
struct Point
{
double x;
double y;
double z;
};
If you are interested only in rotational transforms, you can use the following for 2D transforms:
struct Transform
{
double matrix[2][2];
};
For 3D transforms, you can use:
struct Transform
{
double matrix[3][3];
};
and then add functions to construct points, transforms and performs operations on them. E.g.
Point constructPoint(double x, double y);
Transfrom constructIdentityTransform();
Transfrom constructRotateAroundXTransform(double xrot);
Transfrom constructRotateAroundYTransform(double yrot);
Transfrom constructRotateAroundZTransform(double yrot);
Transform operator*(Transform const& lhs, Transform const& rhs);
Point operator*(Transform const& trans, Point const& p);
I hope this gives you enough information to complete the rest.

C++ vector not inserting

I have the following
std::vector<Cube> well = vector<Cube>();
createCube(well, x, y, z, id);
Later I try to insert a Cube into the vector like this,
void Viewer::createCube(std::vector<Cube> vec, int x, int y, int z, int id) {
float rgb[] = {0.0f, 0.0f, 1.0f};
vec.push_back(Cube(QMatrix4x4(), -1));
int loc = vec.size() - 1;
std::cout << "loc:" << loc << std::endl;
vec.at(vec.size() - 1).matrix.translate(x,y,z);
}
I get output loc = 0.
Why is it not the new Cube to my Vector?
You are passing the vector by value to the createCube function; that means that your vector is copied and then the element is added to the new vector and not to the original one. You can fix it by changing your method signature to:
void Viewer::createCube(std::vector<Cube>& vec, int x, int y, int z, int id)

vector struct in vector struct in

Whats wrong in this code?
#include <vector>
#include <iostream>
typedef struct {
float x, y, z;
} aaa;
typedef struct {
float r, g, b;
std::vector<aaa> a;
} bbb;
typedef struct {
float s, t, p;
std::vector<bbb> b;
} ccc;
int main()
{
aaa o;
std::vector<ccc> c;
c.resize(1); // its OK
c[0].b.resize(4); // its OK
c[0].b[0].a.resize(2); // ??? its allocate 4 instead of 2 but why?
c[0].b[1].a.resize(2); // its OK
c[0].b[2].a.resize(2); // its OK
c[0].b[3].a.resize(2); // its OK
o.x = 1.0f;
o.y = 0.5f;
o.z = 2.567f;
c[0].b[0].a.push_back(o);
o.x = 0.0f;
o.y = 3.4f;
o.z = 3.67f;
c[0].b[0].a.push_back(o);
std::cout << c[0].b[0].a[0].x << std::endl;
std::cout << c[0].b[0].a[0].y << std::endl;
std::cout << c[0].b[0].a[0].z << std::endl;
std::cout << c[0].b[0].a[1].x << std:: endl;
std::cout << c[0].b[0].a[1].y << std::endl;
std::cout << c[0].b[0].a[1].z << std::endl;
system("pause");
return 0;
}
And here is watch window output:
vector c: size = 1; // its OK
vector b: size = 4; // its OK
vector a[0]: size = 4; // ??? (4) ???
vector a[1]: size = 2; // its OK
vector a[3]: size = 2; // its OK
vector a[4]: size = 2; // its OK
std::vector::resize() resizes the vector. So you resize it to 2, and then add 2 more items (with push_back()), so your size is 4.
As mentioned in the comments, if you use
std::cout << "c[0].b[0].a.size() = " << c[0].b[0].a.size() << std::endl;
at different points in the code, you will see the the appropriate sizes.
Member function resize creates new elements if the current size of a vector is less than the size specified in resize().
Member function push_back appends new elements to the vector.
So after statement
c[0].b[0].a.resize(2);
vector a will have two elements. And after these two statements
c[0].b[0].a.push_back(o);
//...
c[0].b[0].a.push_back(o);
it will be appended with another two new elements. Thus as a result vector a will have 4 elements.
If you want to have only two elements then you have to write the following instead of using function push_back
c[0].b[0].a[0] = o;
//...
c[0].b[0].a[1] = o;

Using unordered_map on array of doubles

My main data object is a array of doubles of a length that depends on a specific instantiation of my class. I would like to construct a very simple hash table to store/retrieve these objects, and we can assume that the numbers are generated in a way that is free of numerical error.
int main() {
std::tr1::unordered_map<double*, double*> cache;
double x1[] = { 1.0, 3.14 };
double x2[] = { 1.0, 3.14 };
cache[x1] = x1;
std::cout << "x1: " << cache.count(x1) << std::endl;
std::cout << "x2: " << cache.count(x2) << std::endl;
return 0;
}
The above obviously only compares the pointers, giving the output:
> ./tmp
x1: 1
x2: 0
When I really want to see:
> ./tmp
x1: 1
x2: 1
It's pretty clear how to create custom hashing and equality functions when the size of the arrays are fixed at compile time but I do not know how to make custom functions that depend on a specific instantiation... I created a class below, but I'm not sure if it's useful, or how it could be used.
class Hash_double_vec {
public:
int dim;
Hash_double_vec(int d) { dim = d; }
size_t operator()(const double *x) const{
std::tr1::hash<double> hash_fn;
size_t r = hash_fn(x[0]);
for(int i=1;i<dim;i++) r ^= hash_fn(x[i]);
return r;
}
bool operator()(const double *x, const double *y) const{
for(int i=1;i<dim;i++) if (fabs(x[i]-y[i]) > 1e-10) return false;
return true;
}
};
One way would be to create struct to hold the pointer to the sequence of doubles:
struct DoubleRegion
{
double* p;
size_t size;
};
bool operator==(DoubleRegion a, DoubleRegion b)
{
return a.size == b.size && memcmp(a.p, b.p, a.size) == 0;
}
size_t hash(DoubleRegion dr)
{
size_t h = 0;
for (double* p = dr.p; p != dr.p + dr.size; ++p)
h ^= hash(*p);
return h;
}
And then use it:
unordered_map<DoubleRegion, DoubleRegion> cache;
Of course it is your problem to make sure the lifetime of the backing memory is a superset of the lifetime of the DoubleRegion.
Old Answer:
If you don't know until runtime how big the key and value is going to be, use a std::vector:
unordered_map<vector<double>, vector<double>> cache;
If you know at compile-time how big you can use an std::array:
unordered_map<array<double, N>, array<double, N>> cache;
In both cases the default hashing function will work by value as you want, and you do not need to define a custom one.