如何在MATLAB中的矩阵中的两个已知点之间创建随机路径

时间:2014-03-16 20:38:20

标签: matlab matrix path

如果有一个矩阵和两个已知点,如何在这两个点之间创建一个随机路径(不需要最短):

  1. 可能具有偏差水平的路径
  2. 路径可以是完全随机的(但不是必需的)
  3. 下一步只能来自4个邻居
  4. 离。 带有两个已知点的5x5矩阵:(2,1)(5,5)

    输入后:pt1 = [2,1]; pt2 = [5,5];

    如何使用参数中记录的路径获取如下图案,例如path = [2,1;2,2-;3,2;4,2;4,3;4,4;4,5;5,5]

    X X X X X
    
    o o X X X
    
    X o X X X
    
    X o o o o
    
    X X X X o
    

2 个答案:

答案 0 :(得分:3)

PART A - 目的是找到连接2D域上两个点的线/路径的坐标,使得没有两个相邻坐标彼此对角,即左/右/顶/只有底部。

功能代码

function pts_array = points_array(pt1,pt2)

if pt1(1)==pt2(1)
    if pt2(2)>pt1(2)
        pts_array = [repmat(pt1(1),(pt2(2)-pt1(2)+1),1) (pt1(2):pt2(2))'];
    elseif pt2(2)<pt1(2)
        pts_array = flipud([repmat(pt1(1),(pt1(2)-pt2(2)+1),1) (pt2(2):pt1(2))']);
    else
        pts_array = pt1;
    end
elseif pt1(2)==pt2(2)
    if pt2(1)>pt1(1)
        pts_array = [(pt1(1):pt2(1))' repmat(pt1(2),(pt2(1)-pt1(1)+1),1)];
    elseif pt2(1)<pt1(1)
        pts_array = flipud([(pt2(1):pt1(1))' repmat(pt1(2),(pt1(1)-pt2(1)+1),1)]);
    else
        pts_array = pt1;
    end
else

    gslope1_org = (pt2(2)-pt1(2))/(pt2(1)-pt1(1));
    if gslope1_org <1
        pt1 = fliplr(pt1);
        pt2 = fliplr(pt2);
    end
    gslope1 = (pt2(2)-pt1(2))/(pt2(1)-pt1(1));

    off1 = 1;

    pts_array = [pt1];
    gpt1 = pt1;
    while 1
        slope1 = (pt2(2)-gpt1(2))/(pt2(1)-gpt1(1));
        if (slope1<gslope1)
            gpt1 = [gpt1(1)+off1 gpt1(2)];
            pts_array = [pts_array; gpt1];
        else
            new_y = floor(gpt1(2)+slope1);
            range_y = (gpt1(2)+1 : floor(gpt1(2)+slope1))';
            gpt1 = [gpt1(1) new_y];
            pts_array = [pts_array ; [repmat(gpt1(1),[numel(range_y) 1]) range_y]];
        end
        if isequal(gpt1,pt2)
            break;
        end
    end

    if gslope1_org <1
        pts_array = fliplr(pts_array);
    end
end

function pts_array = points_array_wrap(pt1,pt2) %%// Please remember that this needs points_array.m

x1 = pt1(1);
y1 = pt1(2);
x2 = pt2(1);
y2 = pt2(2);

quad4 = y2<y1 & x2>x1; %% when pt2 is a lower height than pt1 on -slope
quad3 = y2<y1 & x2<x1; %% when pt2 is a lower height than pt1 on +slope
quad2 = y2>y1 & x2<x1; %% when pt2 is a higher height than pt1 on -slope

if quad4
    y2 = y2+ 2*(y1 - y2);
end

if quad2
    y2 = y2 - 2*(y2 - y1);
    t1 = x1;t2 = y1;
    x1 = x2;y1 = y2;
    x2 = t1;y2 = t2;
end

if quad3
    t1 = x1;t2 = y1;
    x1 = x2;y1 = y2;
    x2 = t1;y2 = t2;
end

pts_array = points_array([x1 y1],[x2 y2]);

if quad4
    offset_mat = 2.*(pts_array(:,2)-pt1(2));
    pts_array(:,2) = pts_array(:,2) - offset_mat;
end

if quad3
    pts_array = flipud(pts_array);
end

if quad2
    offset_mat = 2.*(pt1(2)-pts_array(:,2));
    pts_array(:,2) = pts_array(:,2) + offset_mat;
    pts_array = flipud(pts_array);
end

return;

<强>脚本

pt1 = [2 1];
pt2 = [5 5];

pts_array = points_array_wrap(pt1,pt2);

plot(pts_array(:,1),pts_array(:,2),'o'), grid on, axis equal
for k = 1:size(pts_array,1)
    text(pts_array(k,1),pts_array(k,2),strcat('[',num2str(pts_array(k,1)),',',num2str(pts_array(k,2)),']'),'FontSize',16)
end

<强>输出

pts_array =

     2     1
     2     2
     3     2
     3     3
     4     3
     4     4
     4     5
     5     5

<强>剧情

enter image description here

PART B - 目的是找到通过给定空格连接2D域上两个点的线/路径的坐标。

在这种特殊情况下,我们假设有一些空间,只有通过它才能连接路径。 OP不会问这个问题,但我认为分享可能很有意思。因此,对于这个,空格将是OP的问题所示的那些空间。

<强>代码

function your_path = path_calc(mat1,starting_pt,final_pt)

[x1,y1] = find(mat1);
pt1 = [x1 y1];
d1 = pdist2(pt1,final_pt,'euclidean');
[~,ind1] = sort(d1,'descend');
path1 = pt1(ind1,:);
your_path =  path1(find(ismember(path1,starting_pt,'rows')):end,:);

return;

运行 - 1

%%// Data
mat1 = zeros(5,5);
mat1(2,1:2) = 1;
mat1(3,2) = 1;
mat1(4,2:5) = 1;
mat1(5,5) = 1;

starting_pt = [2 1];
final_pt = [5 5];

%%// Path traces
path = path_calc(mat1,starting_pt,final_pt);

Gives -
mat1 =

0     0     0     0     0
1     1     0     0     0
0     1     0     0     0
0     1     1     1     1
0     0     0     0     1


path =

2     1
2     2
3     2
4     2
4     3
4     4
4     5
5     5

运行 - 2

%%// Data
mat1 = zeros(5,5);
mat1(2,1:2) = 1;
mat1(3,2) = 1;
mat1(4,2:5) = 1;
mat1(5,5) = 1;
mat1 = fliplr(mat1');

%%// Notice it starts not from the farthest point this time
starting_pt = [2 3];
final_pt = [5 1];

%%// Path traces
path = path_calc(mat1,starting_pt,final_pt);

Gives

mat1 =

     0     0     0     1     0
     0     1     1     1     0
     0     1     0     0     0
     0     1     0     0     0
     1     1     0     0     0


path =

     2     3
     2     2
     3     2
     4     2
     5     2
     5     1

答案 1 :(得分:1)

要查找从开始到目标的纯随机路径,此函数选择随机方向,检查该方向是否存在有效邻居,如果有,则移动到该新邻居并将其添加到路径。

如果我们在最左边的列中尝试向左移动,则路线可能无效。我们可以事先检查,只选择导致有效邻居的随机方向,但这会使代码复杂化,选择有效邻居的可能性最差为50/50。

function path = random_path(start, goal, board_size)

    m = board_size(1);
    n = board_size(2);
    isInBounds = @(x) x(1) >= 1 && x(1) <= m && x(2) >= 1 && x(2) <= n;

    neighbor_offset = [ 0, -1;    % Neighbor indices:
                       -1,  0;    %        2
                        0,  1;    %    1   x   3
                        1,  0];   %        4
% Edit: get the actual size of our neighbor list
    [possible_moves, ~] = size(neighbor_offset);

    current_position = start;
    path = current_position;

    while sum(current_position ~= goal) > 0
        valid = false;
        while ~valid
% Edit: "magic numbers" are bad; fixed below
%           move = randi(4);
            move = randi(possible_moves);
            candidate = current_position + neighbor_offset(move, :);
            valid = isInBounds(candidate);
        end
        current_position = candidate;
        path = [path; current_position];
    end
end

while条件:

sum(current_position ~= goal) > 0

继续,而sumgoal的至少一个坐标不同。我确信这可以写得更简洁,所以如果有任何关于如何改进的建议,我将不胜感激。

同样,isInBounds匿名函数似乎也有点笨拙,所以任何建议都会受到赞赏。

无论如何,这是输出的样本。由于路径是完全随机的,因此其中一些路径可能会很长:

random_path([2,1], [5,5], [5,5])

ans = 

   2   1 
   3   1 
   2   1 
   3   1 
   3   2 
   4   2 
   4   1 
   5   1 
   4   1 
   4   2 
   3   2 
   3   1 
   2   1 
   1   1 
   2   1 
   3   1 
   3   2 
   4   2 
   4   3 
   4   4 
   4   3 
   4   2 
   4   3 
   5   3 
   4   3 
   3   3 
   4   3 
   4   2 
   4   1 
   4   2 
   4   1 
   4   2 
   4   3 
   4   2 
   5   2 
   5   3 
   5   2 
   4   2 
   3   2 
   3   3 
   3   4 
   3   5 
   3   4 
   2   4 
   3   4 
   4   4 
   5   4 
   5   3 
   4   3 
   3   3 
   3   2 
   4   2 
   4   3 
   4   4 
   5   4 
   5   5