1

Let’s say I have the following 3D discretized space, in which the indexes of the samples/nodes are sequential as it is shown in the picture.

sampled 3D

Now consider only the horizontal middle layer.

My objective is to find a programmatically and iterative rule/s that allow me to run a spiral (like the image or similar, it can start in any direction) over the mid-layer, starting from node 254, as it is shown on the image:

spiral

As you can see in the picture, the yellow crosses show the nodes to be explored. In the first lap these nodes are consecutive while in the second they are separated by 1 node and so on.

I started to solve the problem as follows (pseudocode):

  • I considered size(y) = y = 13

  • Size(z) = z = 3

  • Lap 1:

  1. 254 – z * y = 215
  2. 254 – z * (y + 1) = 212
  3. 254 – z = 251
  4. 254 + z * (y - 1) = 290
  5. 254 + z * y = 293
  6. 254 + z * (y + 1) = 296
  7. 254 + z = 257
  8. 254 – z * (y – 1) = 218
  • Lap 2:
  1. 254 – 3 * z * y = 137
  2. 254 – 3 * z * (y + 2/3) = 131

But I think there may be a simpler, more general rule.

rluq
  • 37
  • 1
  • 8

2 Answers2

1

each direction has constant index increment:

const int dx = 39;
const int dy =  3;
const int dz =  1;

so to make a spiral you just start from start index and increment in current direction i-times then rotate by 90 deg and do the same ... then increment i and do this until desired size is hit ...

You should also add range checking so your spiral will not go outside your array as that would screw things up. By checking actual x,y,z coordinates. So either compute them in parallel or infer them from ix using modular arithmetics so for example something like (C++):

const int dx = 39;
const int dy =  3;
const int dz =  1;

int cw[4]={-dx,-dy,+dx,+dy};    // CW rotation
int ix=254;                     // start point (center of spiral)
int dir=0;                      // direction cw[dir]
int n=5;                        // size
int i,j,k,x,y,z,a;                  // temp

for (k=0,i=1;i<=n;i+=k,k^=1,dir++,dir&=3)
 for (j=1;j<=i;j++)
   {
   int a=ix-1;
   z = a% 3; a/= 3; //  3 is z-resolution
   y = a%13; a/=13; // 13 is y-resolution
   x = a;
   if ((x>=0)&&(x<13)&&(y>=0)&&(y<13)&&(z>=0)&&(z<3))
      {
      // here use point ix
      // Form1->mm_log->Lines->Add(AnsiString().sprintf("%i (%i,%i,%i) %i",ix,x,y,z,i));
      }
   ix+=cw[dir];
   }

producing this output

ix   x,y,z  i
254 (6,6,1) 1
215 (5,6,1) 1
212 (5,5,1) 2
251 (6,5,1) 2
290 (7,5,1) 2
293 (7,6,1) 2
296 (7,7,1) 3
257 (6,7,1) 3
218 (5,7,1) 3
179 (4,7,1) 3
176 (4,6,1) 3
173 (4,5,1) 3
170 (4,4,1) 4
209 (5,4,1) 4
248 (6,4,1) 4
287 (7,4,1) 4
326 (8,4,1) 4
329 (8,5,1) 4
332 (8,6,1) 4
335 (8,7,1) 4
338 (8,8,1) 5
299 (7,8,1) 5
260 (6,8,1) 5
221 (5,8,1) 5
182 (4,8,1) 5
143 (3,8,1) 5
140 (3,7,1) 5
137 (3,6,1) 5
134 (3,5,1) 5
131 (3,4,1) 5

In case you want CCW spiral either reverse the cw[] or instead of dir++ do dir--

In case you want to have changeable screw width then you just increment i by the actual width instead of just by one.

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • In case of not considering limits and from starting point 254, it is not working for me. Output is 254, 212, 254, 212, 254 when it should be: 254, 215, 212, 251, 290, 293, 296, 257, 218, 140, 134, 128, 206, 284, 362, 368, 374, 380, 302, 224, ... – rluq Oct 14 '21 at 10:31
  • @rluq yep I did have a bug in there (did write the code directly in editor) ... I repaired it with new version. However my screw width is `1` and in your case is variable but you did not specify how it changes (on your image first 4 lines are with `width=1` and the rest is `width=2`) so you need to tweak the `i+=k` a bit to match your needs as I have no clue what rules you want to implement for the screw width... – Spektre Oct 14 '21 at 17:35
  • Screw width is always 2 (i.e. there is a space of 1 between "laps"). Moreover, there is one more detail, within first "lap" nodes are explored consecutively but they are separated by 1 node within "lap" 2, 2 nodes within "lap" 3 and so on. Thank you for your review – rluq Oct 14 '21 at 18:32
  • 1
    @rluq just add the variable screw width depending on `i` for example `for (k=0,i=1;i<=n;i+=k,(i<=2)?k^=1:k^=2,dir++,dir&=3)` didn't test it but it should work unless I am off by 1 somwhere – Spektre Oct 15 '21 at 06:33
  • Any idea about incremental separation between nodes within each "lap" (yellow crosses)? – rluq Oct 15 '21 at 16:26
  • @rlug I see absolutely no logic behind them what is the rule? when exactly is the "curved" distance between crosses incremented? – Spektre Oct 15 '21 at 18:17
  • I have changed the second image from the post above in the hope that it will be more explanatory. I think that an approximation to the rule could be to increase the separation between nodes by 1 when spiral changes direction from cw[3] = +dy to cw[0] = -dx, but I am not clear about it – rluq Oct 16 '21 at 07:31
  • might it be possible to keep the current logic you proposed (explore all the nodes from the different "laps") and print only the yellow crosses with additional rule? – rluq Oct 16 '21 at 07:37
  • 1
    @rluq sure ... you just add counter and use only iteration when counter reaches your current distance between crosses ... and increment the distance once dir is incremented 4x (with another counter) – Spektre Oct 16 '21 at 08:10
  • but that rule you imply does not match your spiral – Spektre Oct 16 '21 at 09:46
0

Based on @Spektre answer, this code worked for me:

const int x_res = 13;
const int y_res = 13;
const int z_res = 3;

const int dx = 39;
const int dy =  3;
const int dz =  1;

int cw[4]={-dx,-dy,+dx,+dy};    // CW rotation
int ix=254;                     // start point (center of spiral)
int dir=0;                      // direction cw[dir]
int n=30;                        // size
int i,j,k;

cout << ix << endl;

// first "lap" (consecutive nodes)
for (k=0,i=1;i<=2;i+=k,k^=1,dir++,dir&=3)
    for (j=1;j<=i;j++)
    {
        ix+=cw[dir];
        cout << ix << endl;
    }
i-=1;

int width = 2; //screw width
i+=width;
int dist = 1; //nodes separation
int node_count = 0; //nodes counter

for (k=k,i=i;i<=n;i+=k,k^=width,dir++,dir&=3)
{
    if (dir==1) 
    {
        dist+=1;
    }
    
    for (j=1;j<=i;j++)
    {
        ix+=cw[dir];
        node_count +=1;
        if ((0 < ix) && (ix <= x_res*y_res*z_res))
        {
            if (node_count == dist)
            {
                cout << ix << endl;
                node_count = 0;
            }
        }
        else return 0;
    }
}

return 0;

with this output:

254 215 212 251 290 293 296 257 218 179 140 134 128 206 284 362 368 374 380 302
224 146 68 59 50 83 200 317 434 443 452 461 386 269 152 35
rluq
  • 37
  • 1
  • 8
  • @Spektre ternary condition from `for (k=0,i=1;i<=n;i+=k,(i<=2)?k^=1:k^=2,dir++,dir&=3)` did not work for me so I split original for loop into 2 loops, 1 for first "lap" and other for the rest – rluq Oct 16 '21 at 10:29