diff --git a/include/utComMisc.hrl b/include/utComMisc.hrl index aa75589..55fc11d 100644 --- a/include/utComMisc.hrl +++ b/include/utComMisc.hrl @@ -1,6 +1,6 @@ %% 三目元算符 --define(IIF(Cond, Then, That), case Cond of true -> Then; _ -> That end). --define(IIF(Expr, Expect, Then, ExprRet, That), case Expr of Expect -> Then; ExprRet -> That end). +-define(CASE(Cond, Then, That), case Cond of true -> Then; _ -> That end). +-define(CASE(Expr, Expect, Then, ExprRet, That), case Expr of Expect -> Then; ExprRet -> That end). %% IF-DO表达式 -define(IF(IFTure, DoThat), (IFTure) andalso (DoThat)). diff --git a/src/bStar/bStar.erl b/src/bStar/bStar.erl index f2d4c5d..4adec0d 100644 --- a/src/bStar/bStar.erl +++ b/src/bStar/bStar.erl @@ -90,7 +90,7 @@ start_search(#bstar_map{open_list = [CurrentCell | Rest], target = Target} = BSt %% 非自由节点,沿着障碍爬 Dir = get_branchDir(CurrentCell#cell.branch, CurrentCell#cell.dir), Dir2 = Dir + ?MAX_DIRECTION - 1, - Dir3 = ?IIF(Dir2 >= ?MAX_DIRECTION, Dir2 - ?MAX_DIRECTION, Dir2), + Dir3 = ?CASE(Dir2 >= ?MAX_DIRECTION, Dir2 - ?MAX_DIRECTION, Dir2), case get_branch(CurrentCell, CurrentCell#cell.branch, Dir3, BStarMap) of {true, OpenCell, BStarMap2} -> BStarMap3 = close_cell(BStarMap2, CurrentCell), @@ -152,9 +152,9 @@ get_left_right(CurrentCell, NextCell, BranchDir, Dir, #bstar_map{origin = Origin Angle = g_GetDirAngle(Origin#cell.x, Origin#cell.y, Cell2#cell.x, Cell2#cell.y, NextCell#cell.x, NextCell#cell.y), Angle2 = case BranchDir of ?branch_dir_left -> - ?IIF(Angle > 32, 64 - Angle, 0 - Angle); + ?CASE(Angle > 32, 64 - Angle, 0 - Angle); _ -> - ?IIF(Angle > 32, Angle - 64, Angle) + ?CASE(Angle > 32, Angle - 64, Angle) end, Cell4 = Cell3#cell{reel = Count + 1, s = ?cell_state_open, angle = Angle2}, BStarMap2 = save_cell(BStarMap, Cell4), @@ -203,7 +203,7 @@ get_branch(CurrentCell, BranchDir, Dir, BStarMap) -> get_branch([], _CurrentCell, _BranchDir, _Dir, BStarMap) -> {false, BStarMap}; get_branch([Count | Rest], CurrentCell, BranchDir, Dir, #bstar_map{target = Target, map_config = #map_config{weight = Weight, height = Height}} = BStarMap) -> - Dir2 = ?IIF(Dir >= ?MAX_DIRECTION, Dir - ?MAX_DIRECTION, Dir), + Dir2 = ?CASE(Dir >= ?MAX_DIRECTION, Dir - ?MAX_DIRECTION, Dir), NextDir = branchAround(BranchDir, Dir2), Around = around(NextDir), NextX = CurrentCell#cell.x + Around#pos.x, @@ -277,16 +277,16 @@ get_branch2(_CurrentCell, _NextCell, _BranchDir, _NextDir, _Count, BStarMap) -> %% 计算下一个格子属于自由节点还是攀爬节点 get_branch_i(CurrentCell, NextCell, BranchDir, NextDir, Count, #bstar_map{origin = Origin} = _BStarMap) -> Reel = CurrentCell#cell.reel + Count - 1, - Reel2 = ?IIF(Reel < 0, 0, Reel), + Reel2 = ?CASE(Reel < 0, 0, Reel), Angle = g_GetDirAngle(Origin#cell.x, Origin#cell.y, NextCell#cell.x, NextCell#cell.y, CurrentCell#cell.x, CurrentCell#cell.y), Angle2 = case BranchDir of - ?branch_dir_left -> ?IIF(Angle > 32, 64 - Angle, 0 - Angle); - _ -> ?IIF(Angle > 32, Angle - 64, Angle) + ?branch_dir_left -> ?CASE(Angle > 32, 64 - Angle, 0 - Angle); + _ -> ?CASE(Angle > 32, Angle - 64, Angle) end, Angle3 = CurrentCell#cell.angle + Angle2, - {Angle4, Reel3} = ?IIF(Angle3 >= 64, {Angle3 - 64, Reel2 - 4}, {Angle3, Reel2}), + {Angle4, Reel3} = ?CASE(Angle3 >= 64, {Angle3 - 64, Reel2 - 4}, {Angle3, Reel2}), NextCell2 = NextCell#cell{reel = Reel3, s = ?cell_state_open, angle = Angle4}, - ?IIF(NextCell2#cell.reel > 0, NextCell2#cell{branch = BranchDir, dir = NextDir}, NextCell2#cell{branch = ?branch_dir_none, dir = -1, angle = 0}). + ?CASE(NextCell2#cell.reel > 0, NextCell2#cell{branch = BranchDir, dir = NextDir}, NextCell2#cell{branch = ?branch_dir_none, dir = -1, angle = 0}). %% 找下一个自由点 find_next(CurrentCell, BStarMap) -> @@ -318,7 +318,7 @@ get_cell(#bstar_map{cell_dict = Dict, map_config = MapConfig}, X, Y) -> case dict:find({X, Y}, Dict) of {ok, O} -> O; _ -> - CellState = ?IIF(lib_map:is_walkable_by_index(MapConfig, X, Y), ?cell_state_none, ?cell_state_balk), + CellState = ?CASE(lib_map:is_walkable_by_index(MapConfig, X, Y), ?cell_state_none, ?cell_state_balk), #cell{x = X, y = Y, s = CellState} end. @@ -343,8 +343,8 @@ g_GetDirDiff(OriginX, OriginY, TargetX, TargetY, X, Y) -> TargetDir = g_GetDirIndex(OriginX, OriginY, TargetX, TargetY), TestDir = g_GetDirIndex(OriginX, OriginY, X, Y), DirDiff = TargetDir - TestDir, - DirDiff2 = ?IIF(DirDiff < 0, DirDiff + 64, DirDiff), - ?IIF(DirDiff2 > 32, 64 - DirDiff2, DirDiff2). + DirDiff2 = ?CASE(DirDiff < 0, DirDiff + 64, DirDiff), + ?CASE(DirDiff2 > 32, 64 - DirDiff2, DirDiff2). %% 取得方向 g_GetDirAngle(OriginX, OriginY, TargetX, TargetY, X, Y) -> @@ -430,7 +430,7 @@ get_branchAround(CurrentCell, Branch, TestDir, BStarMap) -> get_branchAround([], _CurrentCell, _Branch, _TestDir, _BStarMap) -> false; get_branchAround([Count | Rest], CurrentCell, Branch, TestDir, #bstar_map{map_config = #map_config{weight = Weight, height = Height}} = BStarMap) -> - TestDir2 = ?IIF(TestDir =:= ?MAX_DIRECTION, 0, TestDir), + TestDir2 = ?CASE(TestDir =:= ?MAX_DIRECTION, 0, TestDir), BranchAround = branchAround(Branch, TestDir2), Around = around(BranchAround), NextX = CurrentCell#cell.x + Around#pos.x, diff --git a/src/hexMap/hexMap.erl b/src/hexMap/hexMap.erl new file mode 100644 index 0000000..2fc2267 --- /dev/null +++ b/src/hexMap/hexMap.erl @@ -0,0 +1,178 @@ +%%基于六边形地图的slg后端需要的相关算法 +-module(hexMap). +-include("utComMisc.hrl"). + +-compile([export_all]). + +%%六边形画线算法 算法说明 http://zvold.blogspot.com/2010/01/bresenhams-line-drawing-algorithm-on_26.html +-define(samePoint(SX, SY, TX, TY), SX == TX andalso SY == TY). +lineDraw({SX, SY}, {TX, TY}) -> %% 11 + case ?samePoint(SX, SY, TX, TY) of + true -> + [{SX, SY}]; + _ -> + X_2old = 2 * (TX - SX) + abs(TY rem 2) - abs(SY rem 2), + Y_old = TY - SY, + case abs(Y_old) < abs(X_2old) of + true -> + X_sign = ?CASE(X_2old >= 0, 1, -1), + Y_sign = ?CASE(Y_old >= 0, 1, -1), + X_diff = 3 * abs(X_2old), + Y_diff = 3 * abs(Y_old), + S = 0, + lineDrawH(SX, SY, TX, TY, X_sign, Y_sign, X_diff, Y_diff, abs(X_2old), S, [{SX, SY}]); + _ -> + X_sign = ?CASE(X_2old >= 0, 1, -1), + Y_sign = ?CASE(Y_old >= 0, 1, -1), + X_diff = abs(X_2old), + Y_diff = abs(Y_old), + S = 0, + lineDrawV(SX, SY, TX, TY, X_sign, Y_sign, X_diff, Y_diff, S, [{SX, SY}]) + end + end. + +lineDrawH(SX, SY, TX, TY, X_sign, Y_sign, X_diff, Y_diff, AX_2old, S, Acc) -> + case ?samePoint(SX, SY, TX, TY) of + true -> + Acc; + _ -> + TS = S + Y_diff, + case TS > AX_2old of + true -> + {NX, NY} = dir_point(X_sign, Y_sign, SX, SY), + NS = TS - X_diff, + lineDrawH(NX, NY, TX, TY, X_sign, Y_sign, X_diff, Y_diff, AX_2old, NS, [{NX, NY} | Acc]); + _ -> + {NX, NY} = dir_point(0, X_sign, SX, SY), + NS = TS + Y_diff, + lineDrawH(NX, NY, TX, TY, X_sign, Y_sign, X_diff, Y_diff, AX_2old, NS, [{NX, NY} | Acc]) + end + end. + +lineDrawV(SX, SY, TX, TY, X_sign, Y_sign, X_diff, Y_diff, S, Acc) -> + case ?samePoint(SX, SY, TX, TY) of + true -> + Acc; + _ -> + TS = S + X_diff, + case TS > 0 of + true -> + {NX, NY} = dir_point(X_sign, Y_sign, SX, SY), + NS = TS - Y_diff, + lineDrawV(NX, NY, TX, TY, X_sign, Y_sign, X_diff, Y_diff, NS, [{NX, NY} | Acc]); + _ -> + {NX, NY} = dir_point(-X_sign, Y_sign, SX, SY), + NS = TS + Y_diff, + lineDrawV(NX, NY, TX, TY, X_sign, Y_sign, X_diff, Y_diff, NS, [{NX, NY} | Acc]) + end + end. + +%%六边形视线算法 算法说明 http://zvold.blogspot.com/2010/02/line-of-sight-on-hexagonal-grid.html +lineSight(SX, SY, TX, TY) -> + case ?samePoint(SX, SY, TX, TY) of + true -> + [{SX, SY}]; + _ -> + TwoXOld = 2 * (TX - SX) + abs(TY rem 2) - abs(SY rem 2), + YOld = TY - SY, + SignX = ?CASE(TwoXOld >= 0, 1, -1), + SignY = ?CASE(YOld >= 0, 1, -1), + ADiffX = abs(TwoXOld), + ADiffY = abs(YOld), + S = -2 * ADiffX, + lineSight(SX, SY, TX, TY, SignX, SignY, ADiffX, ADiffY, S, [{SX, SY}]) + end. + +lineSight(SX, SY, TX, TY, SignX, SignY, ADiffX, ADiffY, S, Acc) -> + case ?samePoint(SX, SY, TX, TY) of + true -> + Acc; + _ -> + case S >= 0 of + true -> + {NX, NY} = dir_point(-SignX, SignY, SX, SY), + NS = S - 3 * ADiffY - 3 * ADiffX, + lineSight(NX, NY, TX, TY, SignX, SignY, ADiffX, ADiffY, NS, [{NX, NY} | Acc]); + _ -> + TS = S + 3 * ADiffY, + case TS > -ADiffX of + true -> + {NX, NY} = dir_point(SignX, SignY, SX, SY), + NS = TS - 3 * ADiffX, + lineSight(NX, NY, TX, TY, SignX, SignY, ADiffX, ADiffY, NS, [{NX, NY} | Acc]); + _ -> + case TS < -3 * ADiffX of + true -> + {NX, NY} = dir_point(SignX, -SignY, SX, SY), + NS = TS + 3 * ADiffX, + lineSight(NX, NY, TX, TY, SignX, SignY, ADiffX, ADiffY, NS, [{NX, NY} | Acc]); + _ -> + {NX, NY} = dir_point(0, SignX, SX, SY), + NS = TS + 3 * ADiffY, + lineSight(NX, NY, TX, TY, SignX, SignY, ADiffX, ADiffY, NS, [{NX, NY} | Acc]) + end + end + end + end. + +-define(HexDirRightUp, 1). +-define(HexDirRight, 2). +-define(HexDirRightDown, 3). +-define(HexDirLeftDown, 4). +-define(HexDirLeft, 5). +-define(HexDirLeftUp, 6). + +dir_point(-1, -1, SX, SY) -> + get_point_xy(SX, SY, ?HexDirLeftDown); +dir_point(-1, 1, SX, SY) -> + get_point_xy(SX, SY, ?HexDirLeftUp); +dir_point(1, -1, SX, SY) -> + get_point_xy(SX, SY, ?HexDirRightDown); +dir_point(1, 1, SX, SY) -> + get_point_xy(SX, SY, ?HexDirRightUp); +dir_point(0, -1, SX, SY) -> + get_point_xy(SX, SY, ?HexDirLeft); +dir_point(0, 1, SX, SY) -> + get_point_xy(SX, SY, ?HexDirRight). + +%% ---------------------------------------------------- +%% @doc +%% 根据方向获取坐标 +%% @end +%% ---------------------------------------------------- +get_point_xy(X, Y, D) -> + Bool = (Y rem 2) =:= 0,%% D band 1 等效 + if + Bool ->%%偶数列 + NX = element(D + 1, ?HEXAGON_X) + X, + NY = element(D + 1, ?HEXAGON_Y) + Y, + {NX, NY}; + true -> + NX = element(D + 1, ?HEXAGON_X1) + X, + NY = element(D + 1, ?HEXAGON_Y) + Y, + {NX, NY} + end. + +-define(HEXAGON_X, {0, 1, -1, -1, 0, 0, 0, -1}).%%六边形格子偶数行 +-define(HEXAGON_X1, {1, 1, 0, -1, 0, 1, 0, 0}).%%六边形格子基数行 +-define(HEXAGON_Y, {-1, 0, 1, 0, 0, 1, 0, -1}).%%六边形格子列 +-define(HEXAGON_DIRECTION, [2, 5, 3, 1, 7, 0]).%%六边形格子的方向 + +-define(HEXAGON_DIRECTION_RIGHT_DOWN, 0). %% 右下 +-define(HEXAGON_DIRECTION_RIGHT, 1). %% 右 +-define(HEXAGON_DIRECTION_LEFT_TOP, 2). %% 左上 +-define(HEXAGON_DIRECTION_LEFT, 3). %% 左 +-define(HEXAGON_DIRECTION_RIGHT_TOP, 5). %% 右上 +-define(HEXAGON_DIRECTION_LEFT_DOWN, 7). %% 左下 + +getDirXY(X, Y, Dir) -> + case (Y rem 2) of + 0 -> + NX = element(Dir + 1, ?HEXAGON_X) + X, + NY = element(Dir + 1, ?HEXAGON_Y) + Y, + {NX, NY}; + _ -> + NX = element(Dir + 1, ?HEXAGON_X1) + X, + NY = element(Dir + 1, ?HEXAGON_Y) + Y, + {NX, NY} + end. diff --git a/src/testCase/funTest.erl b/src/testCase/funTest.erl index ebc52d9..e41f6f7 100644 --- a/src/testCase/funTest.erl +++ b/src/testCase/funTest.erl @@ -66,7 +66,7 @@ ok(N) -> ok(N - 1). test(A) -> - ?IIF(lists:keyfind(a, 1, A), false, none, {_, V}, V). + ?CASE(lists:keyfind(a, 1, A), false, none, {_, V}, V). ams1(A) -> ok. ams2(A) -> fun() -> A end.