Reputation: 119
I'm trying to slice a 3d representation of a image. Following factors is known:
Voxels[] is an array of ushorts representing the grayscale of the pixel.
Now i need to slice it in all possible directions. With let we say x, y or z.
I have tree implementations for this, but they have one problem, they don't work with dimensions that are not the same. (Except for get Z Slice, this is working perfectly).
These are the methods:
private ushort[] GetZSlice(int z, ushort[] voxels, int DimensionX, int DimensionY)
{
var res = new ushort[DimensionX * DimensionY];
for(int j = 0; j < DimensionY; j++)
{
for(int i = 0; i < DimensionX; i++)
{
res[j*DimensionX + i] = voxels[z*DimensionX*DimensionY + j*DimensionX + i];
}
}
return res;
}
This method is working perfectly, it does not mather wat i choose as the dimension.
The next two methods, with x or y as depth poses as a harder problem.
private ushort[] GetYSlice(int y, ushort[] voxels, int DimensionX, int DimensionY, int DimensionZ)
{
var res = new ushort[DimensionX * DimensionZ];
for( int i = 0; i < DimensionX; i++)
{
for( int j = 0; j < DimensionX; j++)
{
res[j + i*DimensionX] = voxels[j * DimensionZ * DimensionY + Y*DimensionZ + i]
}
}
return res;
}
private ushort[] GetXSlice(int x, ushort[voxels], int DimensionX, int DimensionY, int DimensionZ)
{
var res = new short[DimensionY * DimensionZ];
for(int i = 0; i < DimensionY; i++)
{
for(int j = 0; j < DimensionZ; j++)
{
res[j + i*DimensionZ] = voxels[i*DimensionY + j*DimensionZ*DimensionX + x]
}
}
return res;
}
How could I improve the last 2 methods so it works with dimensions that are not equal?
Upvotes: 2
Views: 323
Reputation: 51845
Why not make universal slice function using basis vectors? It will be far less code the manage.
Basicly you got U,V
axises each mapped into X,Y
or Z
. And the Slice W
is the third unused axis. So you just loop the U,V and leave W
as is. Each U,V
has a basis vector (ux,uy,uz)
, (vx,vy,vz)
that describes the increment change in x,y,z
coordinates.
I encoded it into my LED cube class
in C++...
//---------------------------------------------------------------------------
class LED_cube
{
public:
int xs,ys,zs,***map;
LED_cube() { xs=0; ys=0; zs=0; map=NULL; }
LED_cube(LED_cube& a) { xs=0; ys=0; zs=0; map=NULL; *this=a; }
~LED_cube() { _free(); }
LED_cube* operator = (const LED_cube *a) { *this=*a; return this; }
LED_cube* operator = (const LED_cube &a);
void _free();
void resize(int _xs,int _ys,int _zs);
void cls(int col); // clear cube with col 0x00BBGGRR
void sphere(int x0,int y0,int z0,int r,int col); // draws sphere surface with col 0x00BBGGRR
void slice (char *uv,int slice,int col); // draws (XY,XZ,YZ) slice with col 0x00BBGGRR
void glDraw(); // render cube by OpenGL as 1x1x1 cube at 0,0,0
};
//---------------------------------------------------------------------------
void LED_cube::slice(char *uv,int slice,int col)
{
// detect basis vectors from uv string
int ux=0,uy=0,uz=0,us=0;
int vx=0,vy=0,vz=0,vs=0;
int x=slice,y=slice,z=slice,u,v,x0,y0,z0;
if (uv[0]=='X') { x=0; ux=1; us=xs; }
if (uv[0]=='Y') { y=0; uy=1; us=ys; }
if (uv[0]=='Z') { z=0; uz=1; us=zs; }
if (uv[1]=='X') { x=0; vx=1; vs=xs; }
if (uv[1]=='Y') { y=0; vy=1; vs=ys; }
if (uv[1]=='Z') { z=0; vz=1; vs=zs; }
// render slice
if ((x>=0)&&(x<xs)&&(y>=0)&&(y<ys)&&(z>=0)&&(z<zs))
for (u=0;u<us;u++,x+=ux,y+=uy,z+=uz)
{
x0=x; y0=y; z0=z;
for (v=0;v<vs;v++,x+=vx,y+=vy,z+=vz)
map[x][y][z]=col;
x=x0; y=y0; z=z0;
}
}
//---------------------------------------------------------------------------
As you can see it is quite nice and simple ... and still can be optimized much more. here usage and output example:
cube.resize(32,16,20);
cube.cls(0x00202020);
cube.slice("XY",5,0x000000FF);
cube.slice("XZ",5,0x0000FF00);
cube.slice("YZ",5,0x00FF0000);
cube.glDraw();
As you got your voxels stored in 1D array then just compute the address from x,y,z
. so map[x][y][z]
will became your voxels[(x*ys*zs)+(y*zs)+z]
or what ever combination of axis order you got. This can be totally encoded into the basis vectors so you can have du=(ux*ys*zs)+(uy*zs)+uz
and dv=...
and increment the address directly not needing any multiplication latter ...
Upvotes: 2