2

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.

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Can you give some examples of what this should look like? Can you post a [mcve]? How would you do this with the P3D renderer? – Kevin Workman Aug 16 '18 at 16:54
  • @KevinWorkman I have changed the question to make it a bit more understandable. There is no error so I can't post a Minimal, Complete, and Verifiable example and true, I can't do 4d with the p3d renderer, in fact that's why I started experimenting with it. – Benedikt Vilji Magnússon Aug 17 '18 at 14:28
  • @BenediktViljiMagnússon this [how should i handle (morphing) 4D objects in opengl?](https://stackoverflow.com/a/44970550/2521214) and all links in there might interest you – Spektre Sep 16 '18 at 06:21
  • @Spektre I was doing this on processing, a Java library for canvases but from what I know about opengl it supports up to 4x4 matrixes and there for up to 4d transformations. There are many articles about 4d projection and rotation, just search for 4d projection on Google. You would also need to not fill the surfaces of the objects by changing the fragment shaders. TL; DR – Benedikt Vilji Magnússon Sep 16 '18 at 12:34

1 Answers1

2

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]
meowgoesthedog
  • 14,670
  • 4
  • 27
  • 40
  • Thanks. This is a way better answer than I thought I would get. – Benedikt Vilji Magnússon Aug 19 '18 at 11:21
  • @BenediktViljiMagnússon the problem is that in ND you need to represent the mesh as set of simplexes to avoid havoc while reducing into 2D for rendering (especially if cross section is used instead of just perspective or orthographic projections) and that is uneasy ... – Spektre Aug 13 '19 at 09:35