1

我有一个大网格(在图像上以灰色表示),分为几个块(每个块的最大宽度为 3 个单位)。现在我想用相应的块划分一个区域(在网格上以红色表示)。

在此处输入图像描述

举个例子,我想要“块区域”(表示为 {X,Y,Width,Height}):

  • 答:{2,3,2,1}
  • B:{4,3,3,1}
  • C:{7,3,1,1}
  • D:{2,4,2,3}
  • ...

我拥有的唯一信息是网格中块的大小(在本例中为 3)和区域的尺寸:{2,3,6,5}(= {X,Y,width,height})

有谁知道如何以有效的方式做到这一点?我想过使用 mround 来计算块的第一个边界,但这会导致死胡同。提前致谢!

4

2 回答 2

1

数学看起来有点奇怪,因为你从 1,1 开始,但这里是它的要点,

  1. 分别查找 X/Y 轴的边界(在网格中可除以块大小的数字)
  2. 所有尺寸都会blocksize,blocksize除了最左边/右边/顶部/底部的盒子
  3. 找到这些特殊盒子的宽度/高度
  4. 将相应的大小放置到相应的边界
  5. 压缩两个列表

-出口([f/2])。

f({X,Y,Width, Height}, BlockSize) ->
    % all sizes will be Blocksize, Blocksize except  special cases 
    % left/right most will have Xfd/Xld
    % top/bottom most will have Yfd/Yld
    Xfd = BlockSize - ( ( X - 1) rem BlockSize) , 
    Xld = (X + Width - 1) rem BlockSize,
    Yfd = BlockSize - ( ( Y - 1) rem BlockSize) , 
    Yld = (Y + Height - 1) rem BlockSize,

    Xs = divs(X, Width, BlockSize, Xfd),
    Ys = divs(Y, Height, BlockSize, Yfd),

    %replace last values
    {Lx, _} = lists:last(Xs),
    Xss = lists:keyreplace(Lx, 1, Xs, {Lx, Xld}),
    {Ly, _} = lists:last(Ys),
    Yss = lists:keyreplace(Ly, 1, Ys, {Ly, Yld}),

    R = merge(Xss, Yss),
    io:format("~p~n", [R]).

merge(X, Y) ->
    XY= lists:foldl(fun(Xx, Acc) ->
            lists:foldl(fun(Yy, Acc1) ->
                [{Xx, Yy} | Acc1]
             end, Acc, Y) 
    end, [], X),
    lists:map(fun({{Xx, W}, {Yy, H}}) ->
            {Xx, Yy, W, H} 
    end , XY).

divs(X, W, BlockSize, Fd) ->
    R = [{X, Fd}  | [{Xs, BlockSize} || Xs<- lists:seq(X, X + W), (Xs - 1) rem BlockSize =:= 0]],
    lists:sort(sets:to_list(sets:from_list(R))).

>[{7,7,1,1}, {7,4,1,3}, {7,3,1,1}, {4,7,3,1}, {4,4,3,3}, {4,3,3,1}, {2,7,2,1}, {2,4,2,3}, {2,3,2,1}]

于 2013-04-05T17:21:57.557 回答
1

为了好玩,我写了这个。

-module(cluster).

-compile([export_all]).

-record(point, {x,y}).
-record(area, {x,y,w,h}).

area2points(A) ->
    [#point{x=X,y=Y} || 
        X <- lists:seq(A#area.x, A#area.x+ A#area.w-1), 
        Y <- lists:seq(A#area.y, A#area.y+ A#area.h-1)].

points2area([]) -> empty;
points2area(L) ->
    lists:foldl(fun(P,Acc) -> fromcorner(P,Acc) end, area(),L).

area() -> #area{}.
area(X,Y,W,H) -> #area{x=X,y=Y,w=W,h=H}.

point() -> #point{}.
point(X,Y) -> #point{x=X,y=Y}.

fromcorner(#point{x=X,y=Y},#area{x=undefined,y=undefined}) -> 
    #area{x=X,y=Y,w=1,h=1};
fromcorner(#point{x=X,y=Y},#area{x=Xa,y=Ya,w=W,h=H}) -> 
    {Xmin,Wn} = case X < Xa of
        true -> {X,Xa + W - X};
        false -> {Xa,max(W, X+1-Xa)}
    end,
    {Ymin,Hn} = case Y < Ya of
        true -> {Y,Ya + H - Y};
        false -> {Ya,max(H, Y+1-Ya)}
    end,
    #area{x=Xmin,y=Ymin,w=Wn,h=Hn}.


split(A,L) ->
    LA = area2points(A),
    [points2area(lists:filter(fun(P) -> lists:member(P,LA) end ,area2points(X))) || X <- L].


test() ->
    Z1 = area(1,1,3,3),
    Z2 = area(4,1,3,3),
    Z3 = area(7,1,3,3),
    Z4 = area(1,4,3,3),
    Z5 = area(4,4,3,3),
    Z6 = area(7,4,3,3),
    Z7 = area(1,7,3,3),
    Z8 = area(4,7,3,3),
    Z9 = area(7,7,3,3),
    World = [Z1,Z2,Z3,Z4,Z5,Z6,Z7,Z8,Z9],
    A = area(2,3,6,5),
    split(A,World).


76> make:all().    
Recompile: ../src/cluster
up_to_date
77> l(cluster).    
{module,cluster}
78> cluster:test().
[{area,2,3,2,1},
 {area,4,3,3,1},
 {area,7,3,1,1},
 {area,2,4,2,3},
 {area,4,4,3,3},
 {area,7,4,1,3},
 {area,2,7,2,1},
 {area,4,7,3,1},
 {area,7,7,1,1}]
79>
于 2013-04-08T12:37:04.663 回答