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!
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
†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.
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
Related
In matlab I have calculated an array representing a stress field of an elliptic cross-section. That I have done by
% Input
a = 4; b = 2; M = 5;
K = pi*a^3*b^3/(a^2+b^2);
% Stress function
y = linspace(-a,a);
z = linspace(-b,b);
[Y,Z] = meshgrid(y,z);
X = 2*M/K*(a^4*Z.^2+b^4*Y.^2)^(1/2)/(a^2+b^2);
At the same time I have an ellipsis defined as
t = -pi:0.01:pi;
YEllipsis = a*cos(t);
ZEllipsis = b*sin(t);
I need to remove all components of the array X that lies outside the border of the ellipsis defined above. My aim is to plot the contour of the ellipsis by lines, and plot the stress field (X) with contour lines in the same plot.
Any suggestions on how to do that?
Learn about logical indexing. Here's an article that should get you going.
And here's the code to set all the values of X to zero that lie outside the ellipse. (I assume that's what you mean by "remove all components of the array X that lie outside the border", that is the typical way this is done.)
X(y.^2/a^2 + z.^2/b^2 < 1) = 0;
Or, if you really just want that array, you can do it this way:
XNew = X(y.^2/a^2 + z.^2/b^2 < 1);
I know that to get 10 0's, one can do
A = zeros(10, 1);
To get 10 1's, one can do
A = ones(10, 1);
What about any arbitrary number? Say, I want 10 3's. I have come up with a way of doing it.
A = linspace(3, 3, 10);
Is this satisfactory? Is there a more elegant way of doing this?
Some alternatives:
Using repmat:
A = repmat(3, [5 7]); %// 5x7 matrix filled with the value 3
Using indexing:
A(1:m, 1:n) = x;
Following is a timing comparison between all proposed approaches. As you can see, #Dennis' solutions are the fastest (at least on my system).
Functions:
function y = f1(x,m,n) %// Dennis' "ones"
y = x*ones(m,n);
function y = f2(x,m,n) %// Dennis' "zeros"
y = x+zeros(m,n);
function y = f3(x,m,n) %// Luis' "repmat"
y = repmat(x,[m n]);
function y = f4(x,m,n) %// Luis' "dirty"
y(m,n) = 0;
y(:) = x;
function y = f5(x,m,n) %// Luis' "indexing"
y(1:m,1:n) = x;
function y = f6(x,m,n) %// Divakar's "matrix porod"
y = x*ones(m,1)*ones(1,n);
Benchmarking script for square arrays:
x = 3;
sizes = round(logspace(1,3.7,10)); %// max limited by computer memory
for s = 1:numel(sizes)
n = sizes(s);
m = sizes(s);
time_f1(s) = timeit(#() f1(x,m,n));
time_f2(s) = timeit(#() f2(x,m,n));
time_f3(s) = timeit(#() f3(x,m,n));
time_f4(s) = timeit(#() f4(x,m,n));
time_f5(s) = timeit(#() f5(x,m,n));
time_f6(s) = timeit(#() f6(x,m,n));
end
loglog(sizes, time_f1, 'r.-');
hold on
loglog(sizes, time_f2, 'g.:');
loglog(sizes, time_f3, 'b.-');
loglog(sizes, time_f4, 'm.-');
loglog(sizes, time_f5, 'c.:');
loglog(sizes, time_f6, 'k.:');
xlabel('Array size')
ylabel('Time')
legend('ones', 'zeros', 'repmat', 'dirty', 'indexing', 'matrix prod')
For column arrays: just change the following lines:
sizes = round(logspace(1,3.7,10)).^2; %// max limited by computer memory
n = 1;
m = sizes(s);
For row arrays:
sizes = round(logspace(1,3.7,10)).^2; %// max limited by computer memory
n = sizes(s);
m = 1;
Results for a dual-core CPU, 2-GB RAM, Windows Vista, Matlab R2010b:
Square arrays;
Column arrays;
Row arrays.
There are two basic ways to do this:
A = ones(10,1)*3
B = zeros(10,1)+3
The first one is most commonly used in examples, yet if I am not mistaken, the second one performs slightly better. All in all it is just a matter of taste.
Of course, if you have an existing matrix, there is another simple way:
C = zeros(10,1)
C(:) = 3;
And for completeness, the repmat solution as suggested by #Luis is also fine.
As an alternative, a matrix multiplication (which is supposed to be pretty fast on MATLAB) based method could be also be suggested for 2D or multidimensional array assignment work.
Thus, assuming m as rows, n as columns and x as the value to be assigned for all elements, the code would be -
y = x*ones(m,1)*ones(1,n);
I need a way of obtaining a Lx2 trajectory from a Nx2 array of points, i.e. a way of connecting those points into a single trajectory (for example, create a 10000x2 array of points from a 5x2 array of points). I have tried using interp1 and interp2 but either I don't fully understand them or they don't do what I need.
It sounds like you need to be using interp1 in a loop (i.e. to preserve original order) interpolating between each consecutive pair of points:
X = [10; 10.0001; 9; 48]; %// You can consider something like X = [10;10;9;48]; X=X+rand(size(X))*0.0001 instead of dealing with equal X values manually
Y = [10; 20; 50; 6];
m = 3333; %//num points between nodes
n = m*(length(X)-1);
Yi = zeros(n,1);
Xi = [];
for k = 1:length(X)-1
xi = linspace(X(k), X(k+1), m);
Xi = [Xi, xi];
Yi(((k-1)*m+1):k*m) = interp1(X(k:k+1), Y(k:k+1),xi);
end
plot(X,Y,'or');
hold on
plot(Xi,Yi);
To get a pentagon (not a W) try this looping code with these inputs:
X = [0.25; 0.75; 1; 0.5; 0; 0.25];
Y = [0; 0; 1; 1.8; 1; 0];
Result:
I have a dwc = [3001 x 2 double] which more or less is a sin function, I have a for loop finding top values in dwc(:,2). Lets say that there is a top value in dwc(531,2) which way is best way or what is easy to take dwc(531,1) and dwc(531,2) and make an M = [num_of_top_points x 2 double]?
For the following loop, what do I do?
j = 0;
for i = 2:size(dwcL01,1)-1
if dwcL01(i,2) > dwcL01(i-1,2) && dwcL01(i,2) > dwcL01(i+1,2)
j = j+1;
?? = dwcL01(i,:);
end
end
This is how you complete your loop
j = 0;
M = [];
for i = 2:size(dwcL01,1)-1
if dwcL01(i,2) > dwcL01(i-1,2) && dwcL01(i,2) > dwcL01(i+1,2)
j = j+1;
M(j, :) = dwcL01(i, :);
end
end
But you could do this much more efficiently by vectorizing
%//Some example data
x = -4*pi:0.5:4*pi;
y = cos(x);
dwcL01 = [x(:), y(:)]; %// (:) just makes it a column
%// Finding the peaks using diff and sign. Note that I add the first element to the beginning as diff reduces the size by one so this prevents offsetting
F = diff(sign(diff([dwcL01(1,2);dwcL01(:,2)]))) < 0;
M = [dwcL01(F,:)', dwcL01(F,:)'];
plot(x, y, M(:,1), M(:,2), '*r')
How that works is first we find the difference of each element consecutive element pair. Now when the sign changes, that means we've hit a max or min. If the sign change is negative then the gradient went from positive to negative which is a max. So I use diff(sign()) to find the points where the sign changes and then > 0 to create a logical matrix with false everywhere expect for the max. Then I use logical indexing to extract the max.
You could append it to a matrix (let's call it dwcL01_max) - this isn't the fastest way because the matrix size changes each loop but it works:
dwcL01_max = [dwcL01_max dwcL01(i,:)];
The other option would be to use the builtin findpeaks (from the signal proc toolbox)
[~, dwcL01_peaks] = findpeaks(dwcL01(:,2));
dwcL01_max = dwcL01(dwcL01_peaks, :);
This question is similar to this, but instead of an array that represents a square, I need to transpose a rectangular array.
So, given a width: x and a height: y, my array has x*y elements.
If width is 4 and height is 3, and I have:
{0,1,2,3,4,5,6,7,8,9,10,11}
which represents the matrix:
0 1 2 3
4 5 6 7
8 9 10 11
I would like:
{0,4,8,1,5,9,2,6,10,3,7,11}
I know how to do it by making a new array, but I'd like to know how to do it in place like the solution for the previously mentioned question.
A simple way to transpose in place is to rotate each element into place starting from the back of the matrix. You only need to rotate a single element into place at a time, so for the example, starting with [0,1,2,3,4,5,6,7,8,9,a,b], you get:
0,1,2,3,4,5,6,7,8,9,a,b, // step 0
,b, // step 1
,8,9,a,7, // step 2
4,5,6,8,9,a,3, // step 3
,a, // step 4
,8,9,6, // step 5
,4,5,8,9,2, // step 6
,9, // step 7
,8,5, // step 8
,4,8,1, // step 9
,8, // step 10
,4, // step 11
0, // step 12
(This just shows the elements rotated into their final position on each step.)
If you write out how many elements to rotate for each element (from back to front), it forms a nice progression. For the example (width= 4, height= 3):
1,4,7,1,3,5,1,2,3,1,1,1
Or, in a slightly better structured way:
1,4,7,
1,3,5,
1,2,3,
1,1,1
Rotations of 1 element are effectively no-ops, but the progression leads to a very simple algorithm (in C++):
void transpose(int *matrix, int width, int height)
{
int count= width*height;
for (int x= 0; x<width; ++x)
{
int count_adjustment= width - x - 1;
for (int y= 0, step= 1; y<height; ++y, step+= count_adjustment)
{
int last= count - (y+x*height);
int first= last - step;
std::rotate(matrix + first, matrix + first + 1, matrix + last);
}
}
}
One way to do this, is to move each existing element of the original matrix to its new position, taking care to pick up the value at the destination index first, so that it can also be moved to its new position. For an arbitrary NxM matrix, the destination index of an element at index X can be calculated as:
X_new = ((N*X) / (M*N)) + ((N*X) % (M*N))
where the "/" operator represents integer division (the quotient) and the "%" is the modulo operator (the remainder) -- I'm using Python syntax here.
The trouble is that you're not guaranteed to traverse all the elements in your matrix if you start at an arbitrary spot. The easiest way to work around this, is to maintain a bitmap of elements that have been moved to their correct positions.
Here's some Python code that achieves this:
M = 4
N = 3
MN = M*N
X = range(0,MN)
bitmap = (1<<0) + (1<<(MN-1))
i = 0
while bitmap != ( (1<<MN) - 1):
if (bitmap & (1<<i)):
i += 1
xin = X[i]
i = ((N*i)/MN) + ((N*i) % MN)
else:
xout = X[i]
X[i] = xin
bitmap += (1<<i)
i = ((N*i)/MN) + ((N*i) % MN)
xin = xout
print X
I've sacrificed some optimisation for clarity here. It is possible to use more complicated algorithms to avoid the bitmap -- have a look at the references in the related Wikipedia article if you're really serious about saving memory at the cost of computation.