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