6

I have a 2D grid as follow and want to start from X, Y and save the corner of a window (W) and overlap of (OP). I have tried these codes, but non of them are fit to my purpose.

As it is demonstrated, I want to start from a random point (black cell) and save the corner locations (shown by black circles) of each new window in a spiral loop. The algorithm should be used for any grid sizes (not square necessarily) and any start point locations.

Matlab also has a function (spiral) that is similar to what I want, but it does not take a grid, window size and overlap (OP).

I expect to have the following output for this figure: (8,12) (11,12) (11,9) (8,9) (4,9) (4,12) (4,15) ...

I am using the following codes which starts from a corner and fill the matrix step-by-step using the defined W, OP and Matrix size:

W = [10 12];
OP = [4 3];

M = zeros(100,110);

for i=[1:W(1)-OP(1):size(M,1)-W(1), size(M,1)-W(1)+1]
  for j=[1:W(2)-OP(2):size(M,2)-W(2), size(M,2)-W(2)+1]
      block = rand(W(1),W(2));
      M(i:i+W(1)-1, j:j+W(2)-1) = block;
      imagesc(M); axis equal tight xy
      pause(.1)
  end;
end;

So, in a more clear way, how should I change the "above" code in order to start from a location(x,y) and spirally fill the whole matrix according to W, OP and size(M).

Thanks!

Community
  • 1
  • 1
Sam
  • 939
  • 5
  • 14
  • 41
  • 1
    The figure is very unclear. I can't tell which locations you want saved. – rayryeng Apr 06 '15 at 06:02
  • 1
    Could you use minimal sample input data and tell us the expected output? Also, the overlap region could be more than one element wide, right? – Divakar Apr 06 '15 at 06:29
  • I edited the question. Yes, OP can be more than one element. – Sam Apr 06 '15 at 06:36
  • I don't see any `spiral` function in the documentation. Do you have a reference ? – Ratbert Apr 06 '15 at 10:19
  • Also, how do you want to handle the boundaries ? Does the spiral stops when it reaches a boundary or does it continue ? If it continues, it may generate big jumps from one sub-array to the next, without any overlap. – Ratbert Apr 06 '15 at 10:26
  • Here is what I found in Matlab's help: spiral(n) is an n-by-n matrix with elements ranging from 1 to n^2 in a rectangular spiral pattern. – Sam Apr 06 '15 at 17:09
  • Yes, I want it to be stopped when reaches the boundaries. – Sam Apr 06 '15 at 17:11
  • @Ratbert: `spiral` can be found in the demo folder, type in `doc spiral` or `edit spiral` – Daniel Apr 08 '15 at 23:50
  • 1
    @Sam: I assume your example should be `(8,12) (11,12) (11,9) (8,9) (5,9) (5,12) (5,15)` so the step is always 3? – Daniel Apr 08 '15 at 23:54
  • @Sam: Your example does not match the code example. Your code example obviously uses (rows,cols) while your image and the numbers use (x,y) coordinates. If it matters in which direction the spiral starts, please add a numeric example matching the values in the code. First four values are enough. – Daniel Apr 10 '15 at 22:31
  • Yes, they do not match, because I do not know the code! I brought those codes to show how the W and OP works. – Sam Apr 10 '15 at 22:35
  • @Sam: Let's assume in this piece of code your starting point is `[19,28];` (lower left corner). What are the first three points you expect? `[19,28],[25,28],[25,19]` or `[19,28],[25,28],[25,37]` or some other variation? Both match the `W` and `OP` – Daniel Apr 10 '15 at 22:41
  • it will be [19 28], [25 28], [25 28-(12-3)] which 3 is the OP in y direction. So, your first one is correct. – Sam Apr 10 '15 at 23:16

2 Answers2

10

The basic problem

Let the data be defined as:

step = 3;  %// step size
x0 = 8;    %// x coordinate of origin
y0 = 12;   %// y coordinate of origin
N = 32;    %// number of steps

Then the coordinates of the spiral can be obtained as values in the complex plane as follows:

z = x0+1j*y0 + step*cumsum([0 -1j.^(-floor(sqrt(4*(0:N)+1))-1)]);

Of course, the x and y coordinates are then

x = real(z);
y = imag(z);

With the example values given above, plot(z,'o-') (or plot(x,y,'o-')) produces the graph

enter image description here

The key was to generate the sequence 1,2,3,3,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,8... I'm indebted to OEIS for solving that part. The sequence turns out to be the integer part of the square root of 4n+1, for n=1,2,3,...

How to include overlap and window size

To take into account overlap, following Daniel's suggestion, subtract its value from step.

To consider window size, N should be large enough so that the spiral reaches some point out of the window boundary; and then only the preceding points would be kept.

Since it's difficult to compute in advance how large N should be, one possible approach is to exponentially increase N in a loop until it is large enough. The exponential increase assures that the number of loop iterations will be small. The code below uses powers of 2 for N.

%// Data
step = 3;     %// step size
overlap = 1;  %// overlap
x0 = 20;      %// x coordinate of origin
y0 = 15;      %// y coordinate of origin
xmin = 0;     %// window boundary: min x
xmax = 40;    %// window boundary: max x
ymax = 30;    %// window boundary: min y
ymin = 0;     %// window boundary: max y

%// Computations
stepov = step-overlap;
N = 8; %// Initial value. Will be increased as needed
done = false;
while ~done
    z = x0+1j*y0 + stepov*cumsum([0 -1j.^(-floor(sqrt(4*(0:N)+1))-1)]);
        %// compute coordinates of N points
    ind = find(real(z)<xmin | real(z)>xmax | imag(z)<ymin | imag(z)>ymax, 1);
        %// find index of first z out of boundary, if any
    done = ~isempty(ind); %// exit if we have reached outside window boundary
    N = N*2; %// increase number of steps for next try
end
z = z(1:ind-1); %// only keep values that are within the boundary
x = real(z);
y = imag(z);

With the data indicated in the code, the obtained graph is as follows. Note that the last point is (38,0). The next point would be (38,-2), which is outside the window boundary.

enter image description here

Community
  • 1
  • 1
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
  • Nice very clever! Plus the fact you're using `1j` for the imaginary unit :) – Benoit_11 Apr 10 '15 at 00:51
  • @Benoit_11 Thanks! I love it when a problem can be solved in a natural manner with complex numbers :-) – Luis Mendo Apr 10 '15 at 00:52
  • Agreed that's very elegant! I made this question a favourite haha – Benoit_11 Apr 10 '15 at 00:57
  • Thanks for your answer. How can I use the described parameters in your script? (OP, Grid size) You already have considered the origin point and step size, but I need to account for OP and Grid size as well. – Sam Apr 10 '15 at 01:01
  • 1
    @Sam: You have to set `step` to `gridsize-op`. When generating the lower left corner, only the distance to the next lower left corner is relevant. – Daniel Apr 10 '15 at 07:17
  • @Sam I didn't know what you meant by overlap. I think I understand it now. If Daniel's suggestion is not what you need, I'll get back to you later – Luis Mendo Apr 10 '15 at 08:38
  • Thanks Luis. This very close to what I need except the boundary! How should I take it into account? because I want to roll back the code to the left part when it reaches to end on right. I mean, I want to cover all of my matrix. – Sam Apr 10 '15 at 18:33
  • @Sam Sorry, I don't understand what you mean about the boundary. My code already stops at the last point which is within or on the boundary. Isn't that what you need? What do you mean by "roll back the code to the left part when it reaches to end on right"? Perhaps add a clearer image in the question? – Luis Mendo Apr 10 '15 at 19:19
  • I think this post and the provided answer (http://stackoverflow.com/questions/20259818/order-making-for-a-matrix-in-matlab) will help to see what I meant by rolling back to the right part. – Sam Apr 10 '15 at 20:14
  • @Sam: As this provides an important part of your question, you should have included this link to your initial question. – Daniel Apr 10 '15 at 20:49
  • Yes, you are right and I am sorry about that, because I thought that my question is clear enough. – Sam Apr 10 '15 at 20:52
  • @Sam I agree with Daniel. This changes the question significantly. And I still fail to see the meaning of overlap (but that may be just me) – Luis Mendo Apr 10 '15 at 20:53
  • The meaning of overlap based on the above short code seems to be clear. It is a region that the blocks cover each other. – Sam Apr 10 '15 at 21:13
  • @Sam But is _overlap_ (OP) an input or a result? You can't specify an arbitrary overlap _and_ have the window filled exactly – Luis Mendo Apr 10 '15 at 21:27
  • Inputs: W, OP, Grid size, Starting point; Output: corner locations – Sam Apr 10 '15 at 21:44
3

Here is a piece of code which produces the expected output. There where only minor changes to the spiral_generic necessary to match your requirements:

function demo()
spiral_generic([10,11],[3,4])
W = [10 12];
OP = [4 3];
%make sure your start point is really on the grid of r and c, this is not checked!
start = [19,28];
M = zeros(100,110);
r=[1:W(1)-OP(1):size(M,1)-W(1), size(M,1)-W(1)+1];
c=[1:W(2)-OP(2):size(M,2)-W(2), size(M,2)-W(2)+1];
startindex=[find(r==start(1),1,'first'),find(c==start(2),1,'first')];
A=spiral_generic([numel(r),numel(c)],startindex);
[~,idx]=sort(A(:));
[ridx,cidx]=ind2sub(size(A),idx);
%blocks contains the lower left corners in order of processing.
blocks=[r(ridx);c(cidx)];
for blockindex=blocks
       block = rand(W(1),W(2));
       M(blockindex(1):blockindex(1)+W(1)-1, blockindex(2):blockindex(2)+W(2)-1) = block;
       imagesc(M);
       pause(.1)
end

end
function A = spiral_generic(n, P)
% Makes NxN matrix filled up spirally starting with point P
  r = max([P - 1, n - P]);              % Radius of the bigger matrix
  M = spiral(2 * r + 1);                % Bigger matrix itself
  M = permute(M,[2,1]);                 % changing start direction of the spiral
  M = M(:,end:-1:1);                    % chaning spin orientation
  C = r + 1 - (P - 1);                  % Top-left corner of A in M
  A = M(C(1):C(1)+n(1)-1, C(2):C(2)+n(2)-1);  % Get the submatrix
  [~, order] = sort(A(:));              % Get elements' order
  A(order) = 1:(n(1)*n(2));                     % Fill with continous values
end
Daniel
  • 36,610
  • 3
  • 36
  • 69
  • Does it work for square matrix? my matrix is not square and it has a size of 101x200 and my window size is not square and it is 20x15 and the overlap is 5 – Sam Apr 09 '15 at 00:05
  • @Sam: Updated, required minor changes. – Daniel Apr 09 '15 at 00:28
  • Can I define the start point? ("center" in your code), because my start point is not in the center of matrix. you can see that the black cell is not in the center if you look at the above figure. – Sam Apr 09 '15 at 02:02
  • Yes, centre can be changed. You did not describe how it should behave when the borders are reached, so the term `floor(min(center./window_size))*2+1` probably needs to be changed. – Daniel Apr 10 '15 at 07:18
  • I edited the question to show my requirement exactly – Sam Apr 10 '15 at 19:00
  • I get [this] (https://www.dropbox.com/s/dh44712m9azctav/spiral_out.png?dl=0) which is different from what I need! – Sam Apr 11 '15 at 16:32
  • Do you get a similar result? – Sam Apr 11 '15 at 16:42
  • 1
    I corrected it using this: for blockindex=1:size(blocks,2) block = rand(W(1),W(2)); M(blocks(1,blockindex):blocks(1,blockindex)+W(1)-1, blocks(2,blockindex):blocks(2,blockindex)+W(2)-1) = block; imagesc(M); axis equal tight xy pause(.1) end – Sam Apr 11 '15 at 16:54
  • There was a typo in my code, now it produces the same results. – Daniel Apr 11 '15 at 19:07