1 /** This file is part of Shapes.
3 ** Shapes is free software: you can redistribute it and/or modify
4 ** it under the terms of the GNU General Public License as published by
5 ** the Free Software Foundation, either version 3 of the License, or
8 ** Shapes is distributed in the hope that it will be useful,
9 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ** GNU General Public License for more details.
13 ** You should have received a copy of the GNU General Public License
14 ** along with Shapes. If not, see <http://www.gnu.org/licenses/>.
16 ** Copyright 2014 Henrik Tidefelt
19 ##needs ..Shapes..Data / seq-support
22 ##lookin ..Shapes..Data
23 ##lookin ..Shapes..Geometry
24 ##lookin ..Shapes..Layout
25 ##lookin ..Shapes..Graphics
27 /** Graph layout function for nodes on a circle.
28 ** (Ignoring any previous content of node values.)
30 circleGraphLayout: \ g radius:3cm →
32 delta: 360° / g.node_count
33 [g.with_node_values [fmap (\ node → (> coords:radius*[dir node.index*delta] <)) g.nodes]]
36 /** Basic rendering of a graph with nodes layout.
38 renderMultiGraph: \ g →
40 /** Rendering parameters **/
41 nodeRadius: 0.75 * Text..@size
42 multiplicityRadius: 0.7 * Text..@size
44 /** A circle at each node. **/
45 nodeCircles: [g.nodes.foldl \ s n → (s & [[shift n.value.coords] stroke[][circle nodeRadius]]) null]
48 nodeKeys: [g.nodes.foldl \ s n → (s & [[shift n.value.coords] (Text..newText << (String..newString << n.key) ) >> center_x >> [shift (0,~0.5*nodeRadius)]]) null]
50 /** Draw each multiedge as a straigt line between the nodes. **/
53 source: me.source.value.coords
54 target: me.target.value.coords
56 (source + nodeRadius * tmp.begin.T)--(target + nodeRadius * tmp.end.rT)
59 /** Arrow head for directed multiedges. **/
60 edgeArrow: [ShapesArrow width:4bp ...]
62 /** A label showing the multiplicity of a multiedge, positioned inside an imaginary circle of radius multiplicityRadius. **/
63 multiplicityLabel: \ count →
64 (Text..newText << (String..newString << [String..sprintf `(%d)´ count]) ) >> center_x >> [shift (0,~0.5 * multiplicityRadius)]
66 /** Stroke an edge path and add a multiplicity label to the side of the stroke. **/
70 sl: [p [Numeric..Math..abs p]/2]
71 (Traits..@width: 3 * Traits..@width | [stroke p head:[if me.directed? edgeArrow NO_ARROW]])
73 [[shift sl.p + sl.N * multiplicityRadius] [multiplicityLabel me.count]]
76 /** Draw all edges. **/
77 edgeStrokes: [g.multiedges.foldl \ s me → (s & [drawMultiEdge me]) null]
79 /** Combine all results. **/
80 nodeCircles & nodeKeys & edgeStrokes
85 g: [graph undirected:true parallel:true
86 nodes: [list 'a 'b 'c]
88 (> 'a 'b label:'even <) (> 'a 'b label:'odd <)
89 (> 'a 'c label:'even <) (> 'a 'c label:'odd <)
90 (> 'b 'c label:'even <) (> 'b 'c label:'odd <)
91 (> 'c 'b label:'even <) (> 'c 'b label:'odd <)
95 /** Apply layout and rendering functions.
97 Text..@size:9bp & Traits..@width:0.3bp | [renderMultiGraph [circleGraphLayout g]]