|
1 | 1 | package wtg |
2 | 2 |
|
3 | 3 | import ( |
4 | | - "fmt" |
5 | | - "math" |
6 | | - "sort" |
7 | | - |
8 | 4 | "github.com/owulveryck/wardleyToGo" |
9 | 5 | "github.com/owulveryck/wardleyToGo/components/wardley" |
10 | | - "gonum.org/v1/gonum/graph/path" |
| 6 | + "gonum.org/v1/gonum/graph/simple" |
11 | 7 | ) |
12 | 8 |
|
13 | | -func computeEvolutionPosition(s string) (int, int, error) { |
14 | | - // stages is an array containing the size of each stage |
15 | | - // for example if the string is |...|....|.....|......| |
16 | | - // then stages is [3,4,5,6] |
17 | | - stages := make([]int, 4) |
18 | | - // cursor is the place of the cursor in its stage (ex: |..x..|, x=3; |x|, x=0) |
19 | | - cursor := 0 |
20 | | - // stage is the actual stage where the cursor is (x) |
21 | | - stage := 0 |
22 | | - evolvedCursor := 0 |
23 | | - evolvedStage := 0 |
24 | | - // Position of each stage |
25 | | - stagePositions := []float64{0, 17.4, 40, 70, 100} |
26 | | - iteratorStage := -1 |
27 | | - iteratorCursor := 0 |
28 | | - x := 0 |
29 | | - sup := 0 |
30 | | - for _, c := range s { |
31 | | - switch c { |
32 | | - case '|': |
33 | | - iteratorCursor = 0 |
34 | | - iteratorStage++ |
35 | | - continue |
36 | | - case 'x': |
37 | | - x++ |
38 | | - cursor = iteratorCursor |
39 | | - stage = iteratorStage |
40 | | - stages[iteratorStage]++ |
41 | | - case '>': |
42 | | - sup++ |
43 | | - evolvedCursor = iteratorCursor |
44 | | - evolvedStage = iteratorStage |
45 | | - stages[iteratorStage]++ |
46 | | - default: |
47 | | - iteratorCursor++ |
48 | | - if iteratorStage < 0 { |
49 | | - return 0, 0, fmt.Errorf("expected | as a first element") |
50 | | - } |
51 | | - if iteratorStage >= len(stages) { |
52 | | - return 0, 0, fmt.Errorf("too many |") |
| 9 | +// SetCoords sets the y anx x axis of the components |
| 10 | +func SetCoords(m wardleyToGo.Map, withEvolution bool) { |
| 11 | + tempMap := &scratchMapchMap{backend: simple.NewDirectedGraph()} |
| 12 | + ns := m.Nodes() |
| 13 | + inventory := make(map[int64]*node) |
| 14 | + for ns.Next() { |
| 15 | + if c, ok := ns.Node().(*wardley.EvolvedComponent); ok { |
| 16 | + n := &node{ |
| 17 | + c: c.Component, |
53 | 18 | } |
54 | | - stages[iteratorStage]++ |
| 19 | + inventory[c.ID()] = n |
| 20 | + tempMap.AddNode(n) |
55 | 21 | } |
56 | | - } |
57 | | - if iteratorStage != 4 { |
58 | | - return 0, 0, fmt.Errorf("expected 5x|") |
59 | | - } |
60 | | - if x != 1 { |
61 | | - return 0, 0, fmt.Errorf("expeted one and only one x") |
62 | | - } |
63 | | - if sup > 1 { |
64 | | - return 0, 0, fmt.Errorf("expeted one or less >") |
65 | | - } |
66 | | - position := 50.0 |
67 | | - if stages[stage] != 0 { |
68 | | - percentageInCurrentStage := float64(cursor+1) / float64(stages[stage]+1) |
69 | | - //log.Printf("\n\t%v\n\tstages: %v\n\tcurrent stage: %v\n\tcursor: %v\n\tpercentage: %v", s, stages, stage, cursor, percentageInCurrentStage) |
70 | | - position = stagePositions[stage] + (stagePositions[stage+1]-stagePositions[stage])*percentageInCurrentStage |
71 | | - } |
72 | | - evolvedPosition := 0.0 |
73 | | - if stages[evolvedStage] != 0 && sup != 0 { |
74 | | - percentageInCurrentStage := float64(evolvedCursor+1) / float64(stages[evolvedStage]+1) |
75 | | - evolvedPosition = stagePositions[evolvedStage] + (stagePositions[evolvedStage+1]-stagePositions[evolvedStage])*percentageInCurrentStage |
76 | | - } |
77 | | - if position >= evolvedPosition && evolvedPosition != 0 { |
78 | | - return 0, 0, fmt.Errorf("cannot have an evolution before the cursor") |
79 | | - } |
80 | | - return int(math.Round(position)), int(math.Round(evolvedPosition)), nil |
81 | | -} |
82 | | - |
83 | | -type nodeSorter []wardleyToGo.Component |
84 | | - |
85 | | -// Len is part of sort.Interface. |
86 | | -func (s nodeSorter) Len() int { |
87 | | - return len(s) |
88 | | -} |
89 | | - |
90 | | -// Swap is part of sort.Interface. |
91 | | -func (s nodeSorter) Swap(i, j int) { |
92 | | - s[i], s[j] = s[j], s[i] |
93 | | -} |
94 | | - |
95 | | -// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter. |
96 | | -func (s nodeSorter) Less(i, j int) bool { |
97 | | - var labelI string |
98 | | - var labelJ string |
99 | | - if current, ok := s[i].(*wardley.Component); ok { |
100 | | - labelI = current.Label |
101 | | - } |
102 | | - if current, ok := s[i].(*wardley.EvolvedComponent); ok { |
103 | | - labelI = current.Label |
104 | | - } |
105 | | - if current, ok := s[j].(*wardley.Component); ok { |
106 | | - labelJ = current.Label |
107 | | - } |
108 | | - if current, ok := s[j].(*wardley.EvolvedComponent); ok { |
109 | | - labelJ = current.Label |
110 | | - } |
111 | | - return labelI < labelJ |
112 | | -} |
113 | | - |
114 | | -func (p *Parser) computeX() { |
115 | | - wide := 100 |
116 | | - layersAndNodes := make(map[int][]wardleyToGo.Component) |
117 | | - nodesIT := p.WMap.Nodes() |
118 | | - allNodes := make([]wardleyToGo.Component, nodesIT.Len()) |
119 | | - for i := 0; nodesIT.Next(); i++ { |
120 | | - current := nodesIT.Node().(wardleyToGo.Component) |
121 | | - allNodes[i] = current |
122 | | - layersAndNodes[current.GetPosition().Y] = append(layersAndNodes[current.GetPosition().Y], current) |
123 | | - } |
124 | | - // sort the nodes to be coherent |
125 | | - sort.Sort(nodeSorter(allNodes)) |
126 | | - // Arrange nodes on the same layer |
127 | | - for _, nodes := range layersAndNodes { |
128 | | - sort.Sort(nodeSorter(nodes)) |
129 | | - nodesNumber := len(nodes) |
130 | | - // if more than one node on the row, dispatch them |
131 | | - if nodesNumber > 1 { |
132 | | - step := wide / (nodesNumber + 1) |
133 | | - for i, n := range nodes { |
134 | | - if n, ok := n.(*wardley.Component); ok { |
135 | | - n.Placement.X = step * (i + 1) |
136 | | - } |
137 | | - if n, ok := n.(*wardley.EvolvedComponent); ok { |
138 | | - n.Placement.X = step * (i + 1) |
139 | | - } |
| 22 | + if c, ok := ns.Node().(*wardley.Component); ok { |
| 23 | + n := &node{ |
| 24 | + c: c, |
140 | 25 | } |
| 26 | + inventory[c.ID()] = n |
| 27 | + tempMap.AddNode(n) |
141 | 28 | } |
142 | 29 | } |
143 | | - // set nodes randomly |
144 | | - for i, current := range allNodes { |
| 30 | + es := m.Edges() |
| 31 | + for es.Next() { |
| 32 | + tempMap.SetEdge(&edge{ |
| 33 | + f: inventory[es.Edge().From().ID()], |
| 34 | + t: inventory[es.Edge().To().ID()], |
| 35 | + visibility: es.Edge().(*wardley.Collaboration).Visibility, |
| 36 | + }) |
| 37 | + } |
| 38 | + maxVisibility := setNodesVisibility(tempMap) |
| 39 | + setY(tempMap, m, maxVisibility) |
| 40 | + if withEvolution { |
| 41 | + maxEvolution := setNodesEvolutionStep(tempMap) |
| 42 | + setX(tempMap, m, maxEvolution) |
| 43 | + } |
| 44 | + // TODO set the graph nodes |
| 45 | +} |
145 | 46 |
|
146 | | - if current.GetPosition().X == 0 { |
147 | | - if current, ok := current.(*wardley.Component); ok { |
148 | | - current.Placement.X = 50 + 4*(i%2) - 4*((i+1)%2) |
149 | | - } |
150 | | - if current, ok := current.(*wardley.EvolvedComponent); ok { |
151 | | - current.Placement.X = 50 + 4*(i%2) - 4*((i+1)%2) |
152 | | - } |
| 47 | +func setY(buf *scratchMapchMap, m wardleyToGo.Map, maxVisibility int) { |
| 48 | + vStep := 50 |
| 49 | + if maxVisibility != 0 { |
| 50 | + vStep = 96 / maxVisibility |
| 51 | + } |
| 52 | + allNodes := buf.Nodes() |
| 53 | + for allNodes.Next() { |
| 54 | + n := allNodes.Node().(*node) |
| 55 | + if c, ok := m.Node(n.ID()).(*wardley.Component); ok { |
| 56 | + c.Placement.Y = n.visibility*vStep + 2 |
153 | 57 | } |
154 | | - } |
155 | | - nodesIT.Reset() |
156 | | - for nodesIT.Next() { |
157 | | - current := nodesIT.Node().(wardleyToGo.Component) |
158 | | - fromIT := p.WMap.From(current.ID()) |
159 | | - // if only one child, set it at the X of the only father, or at the center otherwise |
160 | | - for i := 0; fromIT.Next(); i++ { |
161 | | - child := fromIT.Node().(wardleyToGo.Component) |
162 | | - fathers := p.WMap.To(child.ID()) |
163 | | - if fathers.Len() == 1 && i == 0 { |
164 | | - if child, ok := child.(*wardley.Component); ok { |
165 | | - child.Placement.X = current.GetPosition().X |
166 | | - } |
167 | | - if child, ok := child.(*wardley.EvolvedComponent); ok { |
168 | | - child.Placement.X = current.GetPosition().X |
169 | | - } |
170 | | - } |
| 58 | + if c, ok := m.Node(n.ID()).(*wardley.EvolvedComponent); ok { |
| 59 | + c.Placement.Y = n.visibility*vStep + 2 |
171 | 60 | } |
172 | 61 | } |
173 | | -} |
174 | 62 |
|
175 | | -func (p *Parser) computeY() { |
176 | | - allShortestPaths := path.DijkstraAllPaths(p.WMap) |
177 | | - roots := findRoot(p.WMap) |
178 | | - leafs := findLeafs(p.WMap) |
179 | | - maxDepth := 1 |
180 | | - for _, r := range roots { |
181 | | - for _, l := range leafs { |
182 | | - paths, _ := allShortestPaths.AllBetween(r.ID(), l.ID()) |
183 | | - for _, path := range paths { |
184 | | - currentVisibility := 0 |
185 | | - for i := 0; i < len(path)-1; i++ { |
186 | | - e := p.WMap.Edge(path[i].ID(), path[i+1].ID()) |
187 | | - currentVisibility += e.(*wardley.Collaboration).Visibility |
188 | | - } |
189 | | - if currentVisibility > maxDepth { |
190 | | - maxDepth = currentVisibility |
191 | | - } |
| 63 | +} |
| 64 | +func setX(buf *scratchMapchMap, m wardleyToGo.Map, maxEvolution int) { |
| 65 | + hStep := 50 |
| 66 | + if maxEvolution != 0 { |
| 67 | + hStep = 20 / maxEvolution |
| 68 | + } |
| 69 | + allNodes := buf.Nodes() |
| 70 | + for allNodes.Next() { |
| 71 | + n := allNodes.Node().(*node) |
| 72 | + if nn, ok := m.Node(n.ID()).(*wardley.Component); ok { |
| 73 | + if !nn.Configured { |
| 74 | + nn.Placement.X = n.evolutionStep*hStep + 30 |
| 75 | + nn.Color = Colors["Grey"] |
192 | 76 | } |
193 | 77 | } |
194 | 78 | } |
195 | 79 |
|
196 | | - step := 96 / maxDepth |
197 | | - cs := &coordSetter{ |
198 | | - verticalStep: step, |
199 | | - } |
200 | | - for _, n := range roots { |
201 | | - cs.walk(p.WMap, n, 0) |
202 | | - } |
203 | | -} |
204 | | - |
205 | | -type coordSetter struct { |
206 | | - verticalStep int |
207 | | -} |
208 | | - |
209 | | -func (c *coordSetter) walk(m *wardleyToGo.Map, n *wardley.Component, visibility int) { |
210 | | - n.Placement.Y = 2 + visibility*c.verticalStep |
211 | | - fromIT := m.From(n.ID()) |
212 | | - for fromIT.Next() { |
213 | | - switch fromNode := fromIT.Node().(type) { |
214 | | - case *wardley.Component: |
215 | | - c.walk(m, fromNode, m.Edge(n.ID(), fromNode.ID()).(*wardley.Collaboration).Visibility+visibility) |
216 | | - case *wardley.EvolvedComponent: |
217 | | - c.walk(m, fromNode.Component, m.Edge(n.ID(), fromNode.ID()).(*wardley.Collaboration).Visibility+visibility) |
218 | | - } |
219 | | - } |
220 | 80 | } |
0 commit comments