arrays - una - recorrer un vector en matlab
Bucle espiral en una matriz desde un punto (2)
Tengo una grilla 2D como sigue y quiero comenzar desde X, Y y guardar la esquina de una ventana (W) y la superposición de (OP). He intentado estos códigos, pero ninguno de ellos se ajusta a mi propósito.
Como se demuestra, quiero comenzar desde un punto al azar (celda negra) y guardar las ubicaciones de las esquinas (mostradas por círculos negros) de cada nueva ventana en un ciclo en espiral. El algoritmo debe usarse para cualquier tamaño de cuadrícula (no necesariamente cuadrada) y cualquier ubicación de punto de inicio.
Matlab también tiene una función (espiral) que es similar a la que yo quiero, pero no requiere una cuadrícula, tamaño de ventana y superposición (OP).
Espero tener la siguiente salida para esta figura: (8,12) (11,12) (11,9) (8,9) (4,9) (4,12) (4,15) ...
Estoy usando los siguientes códigos que comienzan desde una esquina y llenan la matriz paso a paso usando el tamaño W, OP y Matrix definido:
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;
Entonces, de una manera más clara, ¿cómo debería cambiar el código "arriba" para comenzar desde una ubicación (x, y) y llenar en espiral toda la matriz de acuerdo con W, OP y el tamaño (M).
¡Gracias!
Aquí hay un fragmento de código que produce el resultado esperado. Allí donde solo hay cambios menores en el spiral_generic necesarios para satisfacer sus requisitos:
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
El problema básico
Deje que los datos se definan como:
step = 3; %// step size
x0 = 8; %// x coordinate of origin
y0 = 12; %// y coordinate of origin
N = 32; %// number of steps
Entonces las coordenadas de la espiral se pueden obtener como valores en el plano complejo de la siguiente manera † :
z = x0+1j*y0 + step*cumsum([0 -1j.^(-floor(sqrt(4*(0:N)+1))-1)]);
Por supuesto, las coordenadas xey son entonces
x = real(z);
y = imag(z);
Con los valores de ejemplo dados anteriormente, el plot(z,''o-'')
(o la plot(x,y,''o-'')
) produce el gráfico
† La clave fue generar la secuencia 1,2,3,3,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,8...
Estoy en deuda con OEIS por resolver esa parte . La secuencia resulta ser la parte entera de la raíz cuadrada de 4n + 1, para n = 1,2,3, ...
Cómo incluir la superposición y el tamaño de la ventana
Para tener en cuenta la superposición, siguiendo la sugerencia de Daniel , reste su valor del step
.
Para considerar el tamaño de ventana, N
debe ser lo suficientemente grande para que la espiral llegue a algún punto fuera del límite de la ventana; y luego solo se mantendrían los puntos precedentes.
Dado que es difícil calcular de antemano qué tan grande debe ser N
, un posible enfoque es aumentar exponencialmente N
en un bucle hasta que sea lo suficientemente grande. El aumento exponencial asegura que el número de iteraciones de bucle será pequeño. El siguiente código usa potencias de 2 para 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);
Con los datos indicados en el código, el gráfico obtenido es el siguiente. Tenga en cuenta que el último punto es (38,0). El siguiente punto sería (38, -2), que está fuera del límite de la ventana.