我有一个大网格(在图像上以灰色显示),分为几个块(每个块最大宽度为3个单位)。现在我想用相应的块划分一个区域(在网格上用红色表示)。
举个例子,我想要'阻挡区域'(代表{X,Y,宽度,高度}):
我所拥有的唯一信息是网格中块的大小(在本例中为3)和区域的尺寸: {2,3,6,5}(= {X,Y,宽度,高度})
有人知道如何以有效的方式做到这一点吗?我想过使用mround来计算块的第一个边界,但这会导致死胡同。提前谢谢!
答案 0 :(得分:1)
数学看起来有点奇怪,因为你从1,1开始,但这是它的要点,
-export([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}]
答案 1 :(得分: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>