


datatype 'a Tree = Node of' a * ('a Tree list)
-record (pnode, {label = "LABEL", pos = 0, children = []}).
fun movetree (Node ((label, x), subtrees), x ': real) =
Node ((label, x + x '), subtrees)
move_ptree ({[], _X}) -> [];
move_ptree ({# pnode {pos = Pos} = Node, X}) ->
Node # pnode {pos = Pos + X}.
type Extent = (real * real) list
-record (extent, {left, right}).
fun moveextent (e: Extent, x) = map (fn (p, q) => (p + x, q + x)) e
move_extent ({# extent {left = Left, right = Right} = Extent, Offset}) ->
Extent # extent {left = Left + Offset, right = Right + Offset};
move_extent ({ExtentList, Offset}) ->
lists: map (fun (Extent) -> move_extent ({Extent, Offset}) end, ExtentList).
fun merge ([], qs) = qs
| merge (ps, []) = ps
| merge ((p, _) :: ps, (_, q) :: qs) = (p, q) :: merge (ps, qs)
merge_extent ({# extent {left = Left}, #extent {right = Right}}) ->
#extent {left = Left, right = Right};
merge_extent ({[], []}) -> [];
merge_extent ({[], Extent}) -> Extent;
merge_extent ({Extent, []}) -> Extent;
merge_extent ({[Left | LeftRest], [Right | RightRest]}) ->
[merge_extent ({Left, Right}) | merge_extent ({LeftRest, RightRest})].
fun mergelist es = fold merge es []
merge_extent_list (ExtentList) ->
lists: foldl (fun (Elem, Acc) -> merge_extent ({Acc, Elem}) end, [], ExtentList).
merge_extent_list (ExtentList) ->
lists: foldl (fun (Elem, Acc) -> merge_extent ({Elem, Acc}) end, [], ExtentList).
[[{extent, -80, -73}],
[{extent, -48, -41}],
[{extent, -16, -9}],
[{extent, 16,23}],
[{extent, 48.55}],
[{extent, 80.87}]]
merge_extent: Ex1: {extent, -48, -41}, Ex2: {extent, -80, -73}
merge_extent: Result: {extent, -48, -73}
merge_extent: Ex1: {extent, -16, -9}, Ex2: {extent, -48, -73}
merge_extent: Result: {extent, -16, -73}
merge_extent: Ex1: {extent, 16,23}, Ex2: {extent, -16, -73}
merge_extent: Result: {extent, 16, -73}
merge_extent: Ex1: {extent, 48.55}, Ex2: {extent, 16, -73}
merge_extent: Result: {extent, 48, -73}
merge_extent: Ex1: {extent, 80,87}, Ex2: {extent, 48, -73}
merge_extent: Result: {extent, 80, -73}
merge_extent_list: Result: [{extent, 80, -73}]

fun rmax (p: real, q: real) = if p> q then p else q fun fit ((_, p) :: ps) ((q, _) :: qs) = rmax (fit ps qs, p - q + 1.0) | fit _ _ = 0.0
fit_extent ({# extent {right = Right}, #extent {left = Left}}) ->
Right - Left +? EXTENT_SEPARATOR;
fit_extent ({[], []}) ->
0;
fit_extent ({[First | FirstRest], [Second | SecondRest]}) ->
erlang: max (fit_extent ({First, Second}), fit_extent ({FirstRest, SecondRest}));
fit_extent ({_ A, _B}) ->
0
-define (EXTENT_SEPARATOR, 15).
fun fitlistl es =
let
fun fitlistl 'acc [] = []
| fitlistl 'acc (e :: es) =
let val x = fit acc e
in
x :: fitlistl '(merge (acc, moveextent (e, x))) es
end
in
fitlistl '[] es
end
fit_extent_list_l (ExtentList) ->
fit_extent_list_l ([], ExtentList).
fit_extent_list_l (_Acc, []) -> [];
fit_extent_list_l (Acc, [Extent | Rest]) ->
X = fit_extent ({Acc, Extent}),
[X | fit_extent_list_l (merge_extent ({Acc, move_extent ({Extent, X})}), Rest)].
fun fitlistr es =
let
fun fitlistr 'acc [] = []
| fitlistr 'acc (e :: es) =
let val x = ~ (fit e acc)
in
x :: fitlistr '(merge (moveextent (e, x), acc)) es
end
in
rev (fitlistr '[] (rev es))
end
fit_extent_list_r (ExtentList) ->
lists: reverse (fit_extent_list_r ([], lists: reverse (ExtentList))).
fit_extent_list_r (_Acc, []) -> [];
fit_extent_list_r (Acc, [Extent | Rest]) ->
X = - fit_extent ({Extent, Acc}),
[X | fit_extent_list_r (merge_extent ({move_extent ({Extent, X}), Acc}), Rest)].
val flipextent: Extent -> Extent = map (fn (p, q) => (~ q, ~ p)) val fitlistr = rev o map ~ o fitlistl o map flipextent o rev
flip_extent (#extent {left = Left, right = Right} = Extent) ->
Extent # extent {left = -Right, right = -Left};
flip_extent (ExtentList) ->
[flip_extent (Extent) || Extent <- ExtentList].
fit_extent_list_r (ExtentList) ->
lists: reverse (
[-X || X <- fit_extent_list_l (
lists: map (
fun flip_extent / 1,
lists: reverse (ExtentList)
)
)]
).
fun mean (x, y) = (x + y) /2.0 fun fitlist es = map mean (zip (fitlistl es, fitlistr es))
mean ({x, y}) ->
trunc ((X + Y) / 2).
fit_extent_list (ExtentList) ->
lists: map (
fun mean / 1,
lists: zip (fit_extent_list_l (ExtentList), fit_extent_list_r (ExtentList))
).
fun design tree =
let
fun design '(Node (label, subtrees)) =
let
val (trees, extents) = unzip (map design 'subtrees)
val positions = fitlist extents
val ptrees = map movetree (zip (trees, positions))
val pextents = map moveextent (zip (extents, positions))
val resultextent = (0.0, 0.0) :: mergelist pextents
val resulttree = Node ((label, 0.0), ptrees)
in
(resulttree, resultextent)
end
in
fst (design 'tree)
end
design_tree (#pnode {label = Label, children = []}) ->
{make_pnode (Label, 0, []), [make_extent (0, 0)]};
design_tree (#pnode {label = Label, children = Children} = Node) ->
{Trees, Extents} = lists: unzip (lists: map (fun design_tree / 1, Children)),
Positions = fit_extent_list (Extents),
PTrees = lists: map (fun move_ptree / 1, lists: zip (Trees, Positions)),
PExtents = lists: map (fun move_extent / 1, lists: zip (Extents, Positions)),
ResultExtent = [make_extent (0, 0) | merge_extent_list (PExtents)],
ResultTree = Node # pnode {pos = 0, children = PTrees},
{ResultTree, ResultExtent}.
-define (LAYER_HEIGHT, 30).
-define (LINE_Y_OFFSET, 10).
-define (LINE_X_OFFSET, 3).
-define (LINE_VERTICAL_LENGTH, 7).
draw_designed_tree (Canvas, X, Y,
#pnode {label = Label, pos = Pos, children = Children}) ->
NewX = X +? LINE_X_OFFSET,
NewY = Y -? LINE_Y_OFFSET,
gs: line (Canvas, [{{fs, [
{NewX, NewY -? LINE_VERTICAL_LENGTH},
{NewX, NewY},
{NewX + Pos, NewY},
{NewX + Pos, NewY +? LINE_VERTICAL_LENGTH}
]}])
gs: text (Canvas, [
{coords, [{X + Pos, Y}]},
{text, Label}
])
lists: map (
fun (Node) ->
draw_designed_tree (Canvas, X + Pos, Y +? LAYER_HEIGHT, Node)
end,
Children),
ok.
Tree = add_pnodes (
add_pnode (
make_pnode ("@"),
add_pnodes (
make_pnode ("B"),
[make_pnode ("C"),
add_pnodes (
make_pnode ("D"),
[make_pnode ("1"),
make_pnode ("2")]
),
make_pnode ("E"),
add_pnodes (
make_pnode ("F"),
[make_pnode ("1"),
make_pnode ("2"),
make_pnode ("3"),
make_pnode ("4"),
make_pnode ("5"),
make_pnode ("6")]
),
add_pnodes (
make_pnode ("G"),
[make_pnode ("1"),
make_pnode ("2"),
make_pnode ("3"),
make_pnode ("4"),
make_pnode ("5")]
),
make_pnode ("H"),
make_pnode ("I"),
make_pnode ("J")]
)
),
[add_pnodes (
make_pnode ("K"),
[make_pnode ("L"),
make_pnode ("M"),
make_pnode ("N"),
make_pnode ("O"),
make_pnode ("P")]
),
make_pnode ("Q"),
make_pnode ("R"),
make_pnode ("S"),
make_pnode ("T")]
),


-define (LETTER_WIDTH, 7).
label_width (Label) ->
? LETTER_WIDTH * length (Label).
design_tree (#pnode {label = Label, children = []}) ->
{make_pnode (Label, 0, []), [make_extent (0, label_width (Label))]};
design_tree (#pnode {label = Label, children = Children} = Node) ->
{Trees, Extents} = lists: unzip (lists: map (fun design_tree / 1, Children)),
Positions = fit_extent_list (Extents),
PTrees = lists: map (fun move_ptree / 1, lists: zip (Trees, Positions)),
PExtents = lists: map (fun move_extent / 1, lists: zip (Extents, Positions)),
ResultExtent = [make_extent (0, label_width (Label)) | merge_extent_list (PExtents)],
ResultTree = Node # pnode {pos = 0, children = PTrees},
{ResultTree, ResultExtent}.
Tree = add_pnodes (
add_pnode (
make_pnode ("@"),
add_pnodes (
make_pnode ("Beta"),
[make_pnode ("Code"),
add_pnodes (
make_pnode ("Dad"),
[make_pnode ("1st"),
make_pnode ("2dn")]
),
make_pnode ("Exit"),
add_pnodes (
make_pnode ("Fall"),
[make_pnode ("111"),
make_pnode ("222"),
make_pnode ("333"),
make_pnode ("444"),
make_pnode ("555"),
make_pnode ("666")]
),
add_pnodes (
make_pnode ("Gravity"),
[make_pnode ("1_milk"),
make_pnode ("2_apple"),
make_pnode ("3_juice"),
make_pnode ("4_banana"),
make_pnode ("5_orange")]
),
make_pnode ("Hope"),
make_pnode ("Illness"),
make_pnode ("joke")]
)
),
[add_pnodes (
make_pnode ("Kernel"),
[make_pnode ("Load"),
make_pnode ("Module"),
make_pnode ("nop"),
make_pnode ("Operator"),
make_pnode ("Point")]
),
make_pnode ("Quit"),
make_pnode ("Rest"),
make_pnode ("Set"),
make_pnode ("Terminate")]
),

-module (drawtree).
-compile (export_all).
-define (EXTENT_SEPARATOR, 15).
-define (LAYER_HEIGHT, 30).
-define (LINE_Y_OFFSET, 10).
-define (LINE_X_OFFSET, 3).
-define (LINE_VERTICAL_LENGTH, 7).
-define (LETTER_WIDTH, 7).
-define (TREE_POS_X, 350).
-define (TREE_POS_Y, 30).
-define (WINDOW_WIDTH, 1000).
-define (WINDOW_HEIGHT, 500).
-record (pnode, {label = "LABEL", pos = 0, children = []}).
-record (extent, {left, right}).
init () ->
S = gs: start ()
Win = gs: window (ui_main_window, S, [{width,? WINDOW_WIDTH}, {height,? WINDOW_HEIGHT}]),
gs: config (Win, {map, true}),
Canvas = gs: canvas (Win, [{x, 0}, {y, 0}, {width,? WINDOW_WIDTH}, {height,? WINDOW_HEIGHT}]),
do_drawings (Canvas),
loop ()
init: stop ().
move_ptree ({[], _X}) -> [];
move_ptree ({# pnode {pos = Pos} = Node, X}) ->
Node # pnode {pos = Pos + X}.
make_extent (Left, Right) ->
#extent {left = Left, right = Right}.
make_pnode (Label) ->
#pnode {label = Label}.
make_pnode (Label, Pos, Children) ->
#pnode {label = Label, pos = Pos, children = Children}.
add_pnode (#pnode {children = Children} = Tree, PNode) ->
Tree # pnode {children = [PNode | Children]}.
add_pnodes (#pnode {children = Children} = Tree, PNodes) ->
Tree # pnode {children = PNodes ++ Children}.
do_drawings (Canvas) ->
Tree = add_pnodes (
add_pnode (
make_pnode ("@"),
add_pnodes (
make_pnode ("Beta"),
[make_pnode ("Code"),
add_pnodes (
make_pnode ("Dad"),
[make_pnode ("1st"),
make_pnode ("2nd")]
),
make_pnode ("Exit"),
add_pnodes (
make_pnode ("Fall"),
[make_pnode ("111"),
make_pnode ("222"),
make_pnode ("333"),
make_pnode ("444"),
make_pnode ("555"),
make_pnode ("666")]
),
add_pnodes (
make_pnode ("Gravity"),
[make_pnode ("1_milk"),
make_pnode ("2_apple"),
make_pnode ("3_juice"),
make_pnode ("4_banana"),
make_pnode ("5_orange")]
),
make_pnode ("Hope"),
make_pnode ("Illness"),
make_pnode ("joke")]
)
),
[add_pnodes (
make_pnode ("Kernel"),
[make_pnode ("Load"),
make_pnode ("Module"),
make_pnode ("nop"),
make_pnode ("Operator"),
make_pnode ("Point")]
),
make_pnode ("Quit"),
make_pnode ("Rest"),
make_pnode ("Set"),
make_pnode ("Terminate")]
),
io: format ("Source = ~ p ~ n", [Tree]),
{DesignedTree, Extents} = design_tree (Tree),
io: format ("DesignedTree = ~ p ~ n", [DesignedTree]),
io: format ("Extents = ~ p ~ n", [Extents]),
draw_designed_tree (Canvas,? TREE_POS_X,? TREE_POS_Y, DesignedTree).
move_extent ({# extent {left = Left, right = Right} = Extent, Offset}) ->
Extent # extent {left = Left + Offset, right = Right + Offset};
move_extent ({ExtentList, Offset}) ->
lists: map (fun (Extent) -> move_extent ({Extent, Offset}) end, ExtentList).
merge_extent ({# extent {left = Left}, #extent {right = Right}}) ->
#extent {left = Left, right = Right};
merge_extent ({[], []}) -> [];
merge_extent ({[], Extent}) -> Extent;
merge_extent ({Extent, []}) -> Extent;
merge_extent ({[Left | LeftRest], [Right | RightRest]}) ->
[merge_extent ({Left, Right}) | merge_extent ({LeftRest, RightRest})].
merge_extent_list (ExtentList) ->
% IMPORTANT: Notice Elem and Acc change!
% fun (Elem, Acc) -> merge_extent ({Acc, Elem}
lists: foldl (fun (Elem, Acc) -> merge_extent ({Acc, Elem}) end, [], ExtentList).
fit_extent ({# extent {right = Right}, #extent {left = Left}}) ->
Right - Left +? EXTENT_SEPARATOR;
fit_extent ({[], []}) ->
0;
fit_extent ({[First | FirstRest], [Second | SecondRest]}) ->
erlang: max (fit_extent ({First, Second}), fit_extent ({FirstRest, SecondRest}));
fit_extent ({_ A, _B}) ->
0
fit_extent_list_l (ExtentList) ->
fit_extent_list_l ([], ExtentList).
fit_extent_list_l (_Acc, []) -> [];
fit_extent_list_l (Acc, [Extent | Rest]) ->
X = fit_extent ({Acc, Extent}),
[X | fit_extent_list_l (merge_extent ({Acc, move_extent ({Extent, X})}), Rest)].
flip_extent (#extent {left = Left, right = Right} = Extent) ->
Extent # extent {left = -Right, right = -Left};
flip_extent (ExtentList) ->
[flip_extent (Extent) || Extent <- ExtentList].
fit_extent_list_r (ExtentList) ->
lists: reverse (
[-X || X <- fit_extent_list_l (
lists: map (
fun flip_extent / 1,
lists: reverse (ExtentList)
)
)]
).
% fit_extent_list_r (ExtentList) ->
% lists: reverse (fit_extent_list_r ([], lists: reverse (ExtentList))).
% fit_extent_list_r (_Acc, []) -> [];
% fit_extent_list_r (Acc, [Extent | Rest]) ->
% X = - fit_extent ({Extent, Acc}),
% [X | fit_extent_list_r (merge_extent ({move_extent ({Extent, X}), Acc}), Rest)].
mean ({x, y}) ->
trunc ((X + Y) / 2).
fit_extent_list (ExtentList) ->
lists: map (
fun mean / 1,
lists: zip (fit_extent_list_l (ExtentList), fit_extent_list_r (ExtentList))
).
label_width (Label) ->
? LETTER_WIDTH * length (Label).
design_tree (#pnode {label = Label, children = []}) ->
{make_pnode (Label, 0, []), [make_extent (0, label_width (Label))]};
design_tree (#pnode {label = Label, children = Children} = Node) ->
{Trees, Extents} = lists: unzip (lists: map (fun design_tree / 1, Children)),
Positions = fit_extent_list (Extents),
PTrees = lists: map (fun move_ptree / 1, lists: zip (Trees, Positions)),
PExtents = lists: map (fun move_extent / 1, lists: zip (Extents, Positions)),
ResultExtent = [make_extent (0, label_width (Label)) | merge_extent_list (PExtents)],
ResultTree = Node # pnode {pos = 0, children = PTrees},
{ResultTree, ResultExtent}.
draw_designed_tree (Canvas, X, Y,
#pnode {label = Label, pos = Pos, children = Children}) ->
NewX = X +? LINE_X_OFFSET,
NewY = Y -? LINE_Y_OFFSET,
gs: line (Canvas, [{{fs, [
{NewX, NewY -? LINE_VERTICAL_LENGTH},
{NewX, NewY},
{NewX + Pos, NewY},
{NewX + Pos, NewY +? LINE_VERTICAL_LENGTH}
]}])
gs: text (Canvas, [
{coords, [{X + Pos, Y}]},
{text, Label}
])
lists: map (
fun (Node) ->
draw_designed_tree (Canvas, X + Pos, Y +? LAYER_HEIGHT, Node)
end,
Children),
ok.
loop () ->
receive
{gs, ui_main_window, destroy, _Data, _Args} ->
ok;
_Other ->
loop ()
end.
Source: https://habr.com/ru/post/91711/
All Articles