Home > OS >  XYZ to a linear value and vice-versa
XYZ to a linear value and vice-versa

Time:04-03

I have my 3D world x, y, z. I can easily convert given coordinates x, y, z to an integer using my macro XYZ:

const ulong WORLD_SIZE_X = 60;
const ulong WORLD_SIZE_Y = 60;
const ulong WORLD_SIZE_Z = 60;
const ulong WORLD_SIZE = WORLD_SIZE_X * WORLD_SIZE_Y * WORLD_SIZE_Z;
#define XYZ(_x, _y, _z) \
    ((_x)   ((_y)*WORLD_SIZE_X)   ((_z)*WORLD_SIZE_X*WORLD_SIZE_Y))

Hence I can allocate a big "linear" array via calloc(WORLD_SIZE, sizeof(Cube)), and I can access to any cube like this (just an example):

for (int z=0; z<=WORLD_SIZE_Z;   z) {
    for (int y=0; y<=WORLD_SIZE_Y;   y) {
        for (int x=0; x<=WORLD_SIZE_X;   x) {
            printf("blabla\n", myWorld(XYZ(x, y, z));
        }
    }
}

So:

  • I can allocate a "linear" array (= much simpler for me than array of array of array)
  • given x, y and z, I can easily find the element I want

And I cant find the right macro that do the opposite: given a long long pos, find x, y and z.

For a 2D array it's simple, it's x = pos % SIZE_X; and y = (int)(pos / SIZE_X);. But for a 3D world how do you do?

CodePudding user response:

Perhaps it is easier if you rewrite your equation:

u = (z * WORLD_SIZE_Y   y) * WORLD_SIZE_X   x;

You can get the individual coordinates with:

x = u % WORLD_SIZE_X;
y = (u / WORLD_SIZE_X) % WORLD_SIZE_Y;
z = (u / WORLD_SIZE_X) / WORLD_SIZE_Y;

CodePudding user response:

The expressions to 'extract' the X, Y and Z ordinates from the combined pos need to reverse the operations that are used to form that position.

  • For X, it will be the same as the 2D case (just taking the value modulo X_SIZE):
    x = pos % X_SIZE.
  • For Y, we can first divide by X_SIZE (to shift-out the X component), then take the result modulo Y_SIZE:
    y = (pos / X_SIZE) % Y_SIZE.
  • For Z, we extend your original operation for the 2D Y, but divide by the product of X_SIZE and Y_SIZE:
    z = pos / (X_SIZE * Y_SIZE)

However, your system would likely be more efficient (avoiding any maths) by defining a struct for the position; assuming the three "world dimensions" will be no greater than 255, we can use single bytes for each element. You can then have an array (1D) of such structures, and can assign all three (x, y, and z) values in one statement – without using macros – by means of a compound literal.

Here's a brief demo:

#include <stdio.h>
#include <stdint.h>

typedef struct {
    uint8_t x;
    uint8_t y;
    uint8_t z;
} pos_type;

int main()
{
    uint8_t x = 37;
    uint8_t y = 42;
    uint8_t z = 123;
    pos_type pos[100];
    pos[3] = (pos_type){ x, y, z }; // Can assign elements using a compound literal
    uint8_t ax = pos[3].x;
    uint8_t ay = pos[3].y;
    uint8_t az = pos[3].z;
    printf("%hhu %hhu %hhu\n", ax, ay, az);
    return 0;
}
  • Related