Search code examples
javavector3dprocessing4d

connecting points in n-dimensional hyper cube


I am experimenting with creating 3d like sketches in processing without using the p3d renderer. I have managed to make a cube but for it I hardcoded all the coordinates and connections and once you want to add another dimension it begins to get a little boring. So I have created a function to create all the coordinates:

float[][] cube(int dims, float w) {
  int outputSize = (int)pow(2, dims);
  float[] temp = new float[dims];
  float[][] res = new float[outputSize][dims];
  Arrays.fill(temp, w);
  res[0] = temp.clone();
  for (int i = 0; i < outputSize - 1; i++) {
    for (int j = dims - 1; true; j--) {
      temp[j] *= -1;
      if (temp[j] < 0) {
        break; 
      }
    }
    res[i + 1] = temp.clone();
  }
  return res;
}

It simply works by using binary so the inputs (2, 1) cube would be:

[[1, 1], [1, -1], [-1, 1], [-1, -1]]

It works fine but the problem is that It only returns the corners but not witch corner to connect but I can't find an efficient way to do that. I need another function that returns what to indices to connect.

Here is an example of what the function should do given the array above:

[[0, 1], [1, 3], [3, 2], [2, 0]]

(the inner arrays may be in a different order)

Is there any known algorithm to connect the corners of a n-dimensional cube?

I am ok with changing the other function if some other point generation helps.


Solution

  • Here is a way to iteratively generate the coordinates and indices together:

    • Start with a cube of dimension n
    • Make two copies of the cube, and place one at each of the extremal coordinates (e.g. -1 and +1) on the n + 1-th axis
    • Make edges to join each pair of corresponding vertices on the cubes

    enter image description here

    You already know that the number of vertices V(n) = 2^n. Since the number of edges added to an n + 1 cube is equal to this (all corresponding vertex pairs), plus those of the copied n cube, the recurrence relation for the number of edges is:

    E(n) = 2 * E(n - 1) + V(n - 1)   // copies + joining edges
    E(1) = 1                         // base case for n = 1
    
    -->  E(n) = n * 2^(n - 1)
    
    n  | E(n)
    -------------
    1  | 1
    2  | 4
    3  | 12
    4  | 32
    5  | 80
    

    This allows one to pre-allocate the number of required edges and calculate index offsets when copying the new cube / adding new edges.


    Code:

    // edge index
    class Edge
    {
       public int A, B;
       public Edge(int a, int b)
       {
          A = a; B = b;
       }
       public Edge shift(int n)
       {
          return new Edge(A + n, B + n);
       }
    }
    
    // cube class
    class Cube
    {
       // I'll leave out the get-functions etc here
       private float[][] m_verts;
       private Edge[] m_edges;
       public Cube(float[][] v, Edge[] e)
       {
          m_verts = v;
          m_edges = e;
       }
    }
    
    Cube cube_N(int dims, float w)
    {
       // base case
       if (dims < 1)
          return null;
    
       // calculate buffer sizes
       int dpow2 = 1 << dims;
       int numVerts = dpow2;
       int numEdges = dims * (dpow2 / 2);
    
       // buffers
       float[] temp = new float[dims];
       float[][] verts = new float[numVerts][];
       Edge[] edges = new Edge[numEdges];
    
       // base case creation
       Arrays.fill(temp, w);
       verts[0] = temp.clone();
       edges[0] = new Edge(0, 1);
    
       // iterative step
       for (int i = 0; i < dims; i++)
       {
          int nV = 1 << i;
          int nE = i * (nV / 2);
    
          // copy + shift vertices
          for (int j = 0; j < nV; j++)
          {
             float[] v = verts[j].clone();
             v[i] = -w;
             verts[nV + j] = v;
          }
    
          // copy + shift previous edges
          for (int j = 0; j < nE; j++)
          {
             edges[nE + j] = edges[j].shift(nV);
          }
    
          // create new edges to join cube copies
          int off = nE * 2;
          for (int j = 0; j < nV; j++)
          {
             edges[off + j] = new Edge(j, nV + j);
          }
       }
    
       return new Cube(verts, edges);
    }
    

    Results for n = 3:

    verts:
    [1, 1,  1], [-1, 1,  1], [1, -1,  1], [-1, -1,  1],
    [1, 1, -1], [-1, 1, -1], [1, -1, -1], [-1, -1, -1]
    edges:
    [0, 1], [2, 3], [0, 2], [1, 3], [4, 5], [6, 7],
    [4, 6], [5, 7], [0, 4], [1, 5], [2, 6], [3, 7]
    

    Results for n = 4:

    verts: 
    [1, 1,  1,  1], [-1, 1,  1,  1], [1, -1,  1,  1], [-1, -1,  1,  1],
    [1, 1, -1,  1], [-1, 1, -1,  1], [1, -1, -1,  1], [-1, -1, -1,  1],
    [1, 1,  1, -1], [-1, 1,  1, -1], [1, -1,  1, -1], [-1, -1,  1, -1],
    [1, 1, -1, -1], [-1, 1, -1, -1], [1, -1, -1, -1], [-1, -1, -1, -1]
    
    edges:
    [0 ,  1], [2 ,  3], [0 ,  2], [1 ,  3], [4,  5], [6 ,  7], [4 ,  6], [5 ,  7],
    [0 ,  4], [1 ,  5], [2 ,  6], [3 ,  7], [8,  9], [10, 11], [8 , 10], [9 , 11],
    [12, 13], [14, 15], [12, 14], [13, 15], [8, 12], [9 , 13], [10, 14], [11, 15],
    [0 ,  8], [1 ,  9], [2 , 10], [3 , 11], [4, 12], [5 , 13], [6 , 14], [7 , 15]