A function to populate an array with maps - c++

I'm pretty new to C++ so I'm not sure I'm going about this problem in the right way. I'm dealing with a 3D array of voxel data and I would like to create a parallel data structure to store isosurface normal vectors. Memory efficiency is an issue so I thought to use a 2D array of maps, which are indexed by an integer and contain a 3D vector.
The idea being the 2D array indexes every x and y coordinate and the maps index only the z coordinates containing a value (typically between 0 and 3 values dispersed along each row of the z axis).
Question 1: how do I create a 2D array of maps like std::map<int, Vector3f> surfaceNormals; ?
Question 2: My idea is declare the 2D array global then to populate it with a function which deals with it by pointer and creates a map for each array cell, is the code below on the right track? the ?????'s indicate where i'm not sure what to put given my uncertainty about Question 1.
In particular am I managing pointers/references/values correctly such as to actually end up storing all the data I need?
????? isoSurfaces1 [256][100];
????? *extractIS(float Threshold, ????? *pointy){
????? *surfacePointer = pointy;
for loop over x and y {
std::map<int, Vector3f> surfaceNormals;
for loop over z {
[ ... find surface voxels and their normal vectors ... ]
Vector3f newNormalVector(x,y,z);
surfaceNormals[zi] = newNormalVector;
}
surfacePointer[x][y] = surfaceNormals;
}
return surfacePointer;
}
extractIS(0.45, isoSurfaces1);

If i understood you correctly, you want to use the coordinate as a std::map key?
You could just create 1 dimensional std::map, and convert the XYZ coordinates into 1 dimensional coordinate system:
int pos1d = z*max_x*max_y+y*max_x+x;
and then just put that to the map key.
Edit: or you could just use a struct with x,y,z as integers as Space_C0wb0y showed, but that will of course take 3x more memory per std::map key, also note that the example i showed will have the maximum cube size: 1625x1625x1625 (if unsigned int), so if you need longer coordinates then use a struct, but note that with structs you have to write comparisor function for the std::map key datatype.
Edit3:
I think this is what you are looking for, as i noticed you used max 256 coordinate value, here is what i came up with:
// NOTE: max 256x256x256 cube coordinates with this struct. change unsigned char to short or int etc if you need larger values.
// also note that if you change to something else than unsigned char, you cant use nor compare the union: v1.Pos > v2.Pos anymore.
// (unless you use unsigned short for each coordinate, and unsigned __int64 for the union Pos value)
union PosXYZ {
struct {
unsigned char x, y, z, padding; // use full 32bits for better performance
};
unsigned __int32 Pos; // assure its 32bit even on 64bit machines
PosXYZ(unsigned char x, unsigned char y, unsigned char z) : x(x), y(y), z(z), padding(0) {} // initializer list, also set padding to zero so Pos can be compared correctly.
};
inline bool operator>(const PosXYZ &v1, const PosXYZ &v2){
return v1.Pos > v2.Pos;
}
typedef map<PosXYZ, Vector3f, greater<PosXYZ> > MyMap;
void extractIS(float Threshold, MyMap &surfacePointer){
for loop over x and y {
for loop over z {
// [ ... find surface voxels and their normal vectors ... ]
Vector3f newNormalVector(x,y,z);
surfacePointer[PosXYZ(x,y,z)] = newNormalVector;
}
}
}
MyMap isoSurfaces1;
extractIS(0.45, isoSurfaces1);
Another way to do this std::map key struct is to just use plain integer value, which you would generate via your own function similar to: ((x << 16) | (y << 8) | z), this will simplify things a little since you dont need the comparisor function for std::map anymore.
#define PosXYZ(x,y,z) (((x) << 16) | ((y) << 8) | (z)) // generates the std::map key for 256x256x256 max cube coords.
typedef map<unsigned __int32, Vector3f, greater<unsigned __int32> > MyMap;
void extractIS(float Threshold, MyMap &surfacePointer){
for loop over x and y {
for loop over z {
// [ ... find surface voxels and their normal vectors ... ]
Vector3f newNormalVector(x,y,z);
surfacePointer[PosXYZ(x,y,z)] = newNormalVector;
}
}
}
MyMap isoSurfaces1;
extractIS(0.45, isoSurfaces1);

First off, a map has a higher memory overhead than a vector. This brings up the question, how many elements are there? Is it feasible to have vectors that are partly empty? Consider the following implementation:
struct 3dvec {
3dvec(int x, int y, int z) : x(x), y(y), z(z) {}
int x;
int y;
int z;
};
std::vector<3dvec> empty_z_vector(4, 3dvec(0, 0, 0));
std::vector< std::vector<3dvec> > data(width*height, empty_z_vector);
You simply keep all values in memory, based on the assumption that only a few of them will be empty, and there will never be more than 4 z-values. You can access the 3dvec at position X, Y, Z like this:
data[X + Y*width][Z]
This is making a lot of assumptions, but in the end, you will have to compare possible solution, because the feasibility depends on the data.

Related

3D Vector - "No instance of overload function?"

Still relatively new to vectors in C++, the aim of this function is to take 4 arguments, 3 of which define the (x , y , z) position of the data being written, and the 4th being the value that is to be written.
as Requested, a picture of the errors is listed:
Picture of code listed above
The issue is under the "push_back" code. the "." after yy.push and xx.push is giving the error "no instance of overloaded function".
If somebody could explain what this means and how to fix it I would greatly appreciate it! :)
double datawrite(vector<unsigned int> xx, vector<unsigned int> yy,
vector<unsigned int> zz, double val) {
//Writes data to the 3d Vector
//finds coordinates for data
vector< vector< vector<unsigned int > > > xx;
vector< vector<unsigned int> > yy;
vector<unsigned int> zz;
//Writes value at proper position
zz.push_back(val);
yy.push_back(zz);
xx.push_back(yy);
//outputs value from vector
return val;
}
So you want a 3d matrix of doubles? First you need to create it:
#include <vector>
std::vector<vector<vector<double>>> matrix;
This creates a 3d matrix, but with 0 size. Next, when you add data to the matrix, you need to make sure the matrix is big enough:
// Co-ords are integers
double datawrite(int x, int y, int z, double val)
{
// Make sure vectors are large enough
if (matrix.size() < x+1) matrix.resize(x+1);
if (matrix[x].size() < y+1) matrix[x].resize(y+1);
if (matrix[x][y].size() < z+1) matrix[x][y].resize(z+1);
// Store the value
matrix[x][y][z] = val;
return val;
}
However, this is a bit messy and leaves the matrix in an incomplete state. For example, if you call datawrite(2, 3, 4, 9.9); this may appear that all indexes < 2,3,4 would be valid, but they are not. For example trying to read matrix[0][0][0] will give you an error.
You could work around this with a dataread function that checks the sizes of the vectors before trying to read from them.
If you know ahead of time how large the matrix is, you can create the entire matrix at once like this:
vector<vector<vector<double>>> matrix(10, vector<vector<double>>(10, vector<double>(10)));
This creates a complete 10x10x10 matrix. This ensures all indexes < 10 will be valid. I prefer this method. Then your function becomes:
double datawrite(int x, int y, int z, double val)
{
// Make sure indexes are valid
if (x >= matrix.size() || y >= matrix[x].size() || z >= matrix[x][y].size()) {
// Up to you what to do here.
// Throw an error or resize the matrix to fit the new data
}
// Store the value
matrix[x][y][z] = val;
return val;
}

Initializing a box with N particles arranged in a specific pattern

I'm new to C++, and as an exercise I'm trying to reproduce what was done by Metropolis et al. (Metropolis Monte Carlo).
What I have done thus far - Made 2 classes: Vector and Atom
class Vector {
public:
double x;
double y;
Vector() {
}
Vector (double x_, double y_) {
x = x_;
y = y_;
}
double len() {
return sqrt(x*x + y*y);
}
double lenSqr() {
return x*x + y*y;
}
};
class Atom {
public:
Vector pos;
Vector vel;
Vector force;
Atom (double x_, double y_) {
pos = Vector(x_, y_);
vel = Vector(0, 0);
force = Vector(0, 0);
}
double KE() {
return .5 * vel.lenSqr();
}
};
I am not certain that the way I have defined the class Atom is... the best way to go about things since I will not be using a random number generator to place the atoms in the box.
My problem:
I need to initialize a box of length L (in my case L=1) and load it with 224 atoms/particles in an offset lattice (I have included a picture). I have done some reading and I was wondering if maybe an array would be appropriate here.
One thing that I am confused about is how I could normalize the array to get the appropriate distance between the particles and what would happen to the array once the particles begin to move. I am also not sure how an array could give me the x and y position of each and every atom in the box.
Metropolis offset (hexagonal) lattice
Well, It seems, that generally you don't need to use array to represent the lattice. In practice most often it may sense to represent lattice as array only if your atoms can naturally move only on the cells (for example as figures in chess). But seems that your atoms can move in any direction (already not practicle to use such rigid structure as array, because it has naturally 4 or 8 directions for move in 2D) by any step (it is bad for arrays too, because in this case you need almost countless cells in array to represent minimal distance step).
So basically what do you need is just use array as storage for your 224 atoms and set particular position in lattice via pos parameter.
std::vector<Atom> atoms;
// initialize atoms to be in trigonal lattice
const double x_shift = 1. / 14;
const double y_shift = 1. / 16;
double x_offset = 0;
for (double y = 0; y < 1; y += y_shift){
for (double x = x_offset; x < 1; x += x_shift){
// create atom in position (x, y)
// and store it in array of atoms
atoms.push_back(Atom(x, y));
}
// every new row flip offset 0 -> 1/28 -> 0 -> 1/28...
if (x_offset == 0){
x_offset = x_shift / 2;
}
else{
x_offset = 0;
}
}
Afterwards you just need to process this array of atoms and change their positions, velocities and what you need else according to algorithm.

Sorting an array of structs in C++

I'm using a particle physics library written in c++ for a game.
In order to draw the particles I must get an array of all their positions like so..
b2Vec2* particlePositionBuffer = world->GetParticlePositionBuffer();
This returns an array of b2Vec2 objects (which represent 2 dimensional vectors in the physics engine).
Also I can get and set their colour using
b2ParticleColor* particleColourBuffer = world->GetParticleColorBuffer();
I would like to get the 10% of the particles with the highest Y values (and then change their colour)
My idea is..
1. Make an array of structs the same size as the particlePositionBuffer array, the struct just contains an int (the particles index in the particlePositionBuffer array) and a float (the particles y position)
2.Then I sort the array by the y position.
3.Then I use the int in the struct from the top 10% of structs in my struct array to do stuff to their colour in the particleColourBuffer array.
Could someone show me how to sort and array of structs like that in c++ ?
Also do you think this is a decent way of going about this? I only need to do it once (not every frame)
Following may help:
// Functor to compare indices according to Y value.
struct comp
{
explicit comp(b2Vec2* particlePositionBuffer) :
particlePositionBuffer(particlePositionBuffer)
{}
operator (int lhs, int rhs) const
{
// How do you get Y coord ?
// note that I do rhs < lhs to have higher value first.
return particlePositionBuffer[rhs].getY() < particlePositionBuffer[lhs].getY();
}
b2Vec2* particlePositionBuffer;
};
void foo()
{
const std::size_t size = world->GetParticleCount(); // How do you get Count ?
const std::size_t subsize = size / 10; // check for not zero ?
std::vector<std::size_t> indices(size);
for (std::size_t i = 0; i != size; ++i) {
indices[i] = i;
}
std::nth_element(indices.begin(), indices.begin() + subsize, indices.end(),
comp(world->GetParticlePositionBuffer()));
b2ParticleColor* particleColourBuffer = world->GetParticleColorBuffer();
for (std::size_t i = 0; i != subsize; ++i) {
changeColor(particleColourBuffer[i])
}
}
If your particle count is low, it won't matter much either way, and sorting them all first with a simple stl sort routine would be fine.
If the number were large though, I'd create a binary search tree whose maximum size was 10% of the number of your particles. Then I'd maintain the minY actually stored in the tree for quick rejection purposes. Then this algorithm should do it:
Walk through your original array and add items to the tree until it is full (10%)
Update your minY
For remaining items in original array
If item.y is less than minY, go to next item (quick rejection)
Otherwise
Remove the currently smallest Y value from the tree
Add the larger Y item to the tree
Update MinY
A binary search tree has a nice advantage of quick insert, quick search, and maintained ordering. If you want to be FAST, this is better than a complete sort on the entire array.

Voxel unique ID in 3D space

i am looking for a way to collect a set of voxels. A voxel is a 3D cell that can be full/empty/unknown and is built upon a point cloud (for data reduction). The voxels collection once built is never modified (destroyed and rebuilt each round), but different kind of access are required (neighborood, iterative on all, direct).
The voxel space is very very sparse, out of order of 1.000.000 possible voxels in space only at most 1000 are used.
So i decided to use a (unordered since using c++)hashmap to collect them (an octree is an overkill i think) with the voxel ID as a key. Now i need a function to convert in both way a 3D point to voxel ID and the ID to the voxel 3D point centroid.
What i find hard is a very fast way to do it, i'd like to have they key as a single int value like:
unsigned int VoxelsMap::pointToVoxelId(const Vector3f & point){
unsigned int id = 0;
int x = (int)floor(roundpoint[0]);
int y = (int)floor(roundpoint[1]);
int z = (int)floor(roundpoint[2]);
id = A-BIJECTIVE-FUNCTION(x, y, z);
return id;
}
but for the bijective function i cant come up with anything very fast (as for the previous casts etc that i dont like for a function that must be used so often (200FPS x ~1000 x 3) ).
So:
is the hashmap a good datastructure (what worries me is the neighborood search)
what can be a function for A-BIJECTIVE-FUNCTION or for the whole function
Thanks.
#include <iostream>
using namespace std;
int main()
{
int x = 2.1474e+009;
int y = -2097152;
int z = -2048;
int rx = x;
int ry = y << 10;
int rz = z << 20;
int hashed = rx + ry + rz;
x = rx;
y = ry >> 10;
z = rz >> 20;
cout << hashed << endl;
cout << x << " " << y << " " << z << endl;
return 0;
}
This hash/unhash method should be the fastest.
Note that I only use 30 bits out of 32 bits of the integer. This allows a maxmimum world size of 4.2950e+009 x 4194304 x 4096. If you want to extend the world limits, you will have to use more/bigger integers.
Hope this can help.
Do you want to collect them space-wise in a way that links every adjacent voxel? If this is what you want, then you could use the Hoshen-Kopelman algorithm in 3D. Writing the code for that should take like a day or two, and you're done. The exmaple in the link is for 2D; expanding that to 3D isn't an issue at all.
Hope this helps.
Why not using a more elaborate key for your hashmap? Instead of a simple int, you could build a tuple with your x,y,z coordinates or implement you own struct. The later option would require implementing operator==() and a hash function. Some information about a good hash function can be found here.

C++ Data Structure for storing 3 dimensions of floats

I've implemented a 3D strange attractor explorer which gives float XYZ outputs in the range 0-100, I now want to implement a colouring function for it based upon the displacement between two successive outputs.
I'm not sure of the data structure to use to store the colour values for each point, using a 3D array I'm limited to rounding to the nearest int which gives a very coarse colour scheme.
I'm vaguely aware of octtrees, are they suitable in this siutation?
EDIT: A little more explanation:
to generate the points i'm repeatedly running this:
(a,b,c,d are random floats in the range -3 to 3)
x = x2;
y = y2;
z = z2;
x2 = sin(a * y) - z * cos(b * x);
y2 = z2 * sin(c * x) - cos(d * y);
z2 = sin(x);
parr[i][0]=x;
parr[i][1]=y;
parr[i][2]=z;
which generates new positions for each axis each run, to colour the render I need to take the distance between two successive results, if I just do this with a distance calculation between each run then the colours fade back and forth in equilibrium so I need to take running average for each point and store it, using a 3dimenrsionl array is too coarse a colouring and I'm looking for advice on how to store the values at much smaller increments.
Maybe you could drop the 2-dim array off and use an 1-dim array of
struct ColoredPoint {
int x;
int y;
int z;
float color;
};
so that the code would look like
...
parr[i].x = x;
parr[i].y = y;
parr[i].z = z;
parr[i].color = some_computed_color;
(you may also wish to encapsulate the fields and use class ColoredPoint with access methods)
I'd probably think bout some kind of 3-d binary search tree.
template <class KEY, class VALUE>
class BinaryTree
{
// some implementation, probably available in libraries
public:
VALUE* Find(const KEY& key) const
{
// real implementation is needed here
return NULL;
}
};
// this tree nodes wil actually hold color
class BinaryTree1 : public BinaryTree<double, int>
{
};
class BinaryTree2 : public BinaryTree<double, BinaryTree1>
{
};
class BinaryTree3 : public BinaryTree<double, BinaryTree2>
{
};
And you function to retreive the color from this tree would look like that
bool GetColor(const BinaryTree3& tree, double dX, double dY, double& dZ, int& color)
{
BinaryTree2* pYTree = tree.Find(dX);
if( NULL == pYTree )
return false;
BinaryTree1* pZTree = pYTree->Find(dY);
if( NULL == pZTree )
return false;
int* pCol = pZTree->Find(dZ);
if( NULL == pCol )
return false;
color = *pCol;
return true;
}
Af course you will need to write the function that would add color to this tree, provided 3 coordinates X, Y and Z.
std::map appears to be a good candidate for base class.