10
10
using PalCalc . Solver ;
11
11
using CommunityToolkit . Mvvm . ComponentModel ;
12
12
using System . Windows . Media . Animation ;
13
+ using QuickGraph . Serialization ;
13
14
14
15
namespace PalCalc . UI . ViewModel . GraphSharp
15
16
{
@@ -33,30 +34,96 @@ public object Clone()
33
34
34
35
// currently assuming left-to-right layout
35
36
internal class BreedingTreeLayoutAlgorithm : DefaultParameterizedLayoutAlgorithmBase < BreedingTreeNodeViewModel , BreedingEdge , BreedingGraph , BreedingTreeLayoutAlgorithmParameters >
36
-
37
37
{
38
38
private Dictionary < BreedingTreeNodeViewModel , Size > _sizes ;
39
+ private Dictionary < IBreedingTreeNode , BreedingTreeNodeViewModel > _viewmodels ;
40
+ private Dictionary < BreedingTreeNodeViewModel , Size > _fullSizes = new Dictionary < BreedingTreeNodeViewModel , Size > ( ) ;
41
+ private Dictionary < BreedingTreeNodeViewModel , Node > _nodesByVm ;
42
+ private Dictionary < IBreedingTreeNode , Node > _nodesByModel ;
43
+
44
+ private class Node
45
+ {
46
+ private BreedingTreeLayoutAlgorithm algo ;
47
+
48
+ public Node ( BreedingTreeLayoutAlgorithm algo , BreedingTreeNodeViewModel asViewModel , IBreedingTreeNode asModel )
49
+ {
50
+ this . algo = algo ;
51
+ AsViewModel = asViewModel ;
52
+ AsModel = asModel ;
53
+ }
54
+
55
+ public BreedingTreeNodeViewModel AsViewModel { get ; }
56
+ public IBreedingTreeNode AsModel { get ; }
57
+
58
+ public Point SelfCenter
59
+ {
60
+ get => algo . VertexPositions [ AsViewModel ] ;
61
+ set => algo . VertexPositions [ AsViewModel ] = value ;
62
+ }
63
+ public Size SelfSize => algo . _sizes [ AsViewModel ] ;
64
+
65
+ public Size FullSize => algo . FullSizeWithChildren ( AsViewModel ) ;
66
+
67
+ public double SelfTopY
68
+ {
69
+ get => SelfCenter . Y - SelfSize . Height / 2 ;
70
+ set
71
+ {
72
+ var p = SelfCenter ;
73
+ p . Y = value + SelfSize . Height / 2 ;
74
+ SelfCenter = p ;
75
+ }
76
+ }
77
+
78
+ public double SelfBottomY
79
+ {
80
+ get => SelfCenter . Y + SelfSize . Height / 2 ;
81
+ set
82
+ {
83
+ var p = SelfCenter ;
84
+ p . Y = value - SelfSize . Height / 2 ;
85
+ SelfCenter = p ;
86
+ }
87
+ }
88
+
89
+ public double FullTopY => SelfCenter . Y - FullSize . Height / 2 ;
90
+ public double FullBottomY => SelfCenter . Y + FullSize . Height / 2 ;
91
+ }
39
92
40
93
public BreedingTreeLayoutAlgorithm ( BreedingGraph visitedGraph , IDictionary < BreedingTreeNodeViewModel , Point > vertexPositions , IDictionary < BreedingTreeNodeViewModel , Size > vertexSizes , BreedingTreeLayoutAlgorithmParameters parameters )
41
94
: base ( visitedGraph , vertexPositions , parameters )
42
95
{
43
96
_sizes = new Dictionary < BreedingTreeNodeViewModel , Size > ( vertexSizes ) ;
97
+ _viewmodels = visitedGraph . Edges . SelectMany ( e => new [ ] { e . Source , e . Target } ) . Distinct ( ) . ToDictionary ( vm => vm . Value ) ;
98
+
99
+ _nodesByModel = new Dictionary < IBreedingTreeNode , Node > ( ) ;
100
+ _nodesByVm = new Dictionary < BreedingTreeNodeViewModel , Node > ( ) ;
101
+ foreach ( var vm in _viewmodels . Values )
102
+ {
103
+ var node = new Node ( this , vm , vm . Value ) ;
104
+ _nodesByModel . Add ( vm . Value , node ) ;
105
+ _nodesByVm . Add ( vm , node ) ;
106
+ }
44
107
}
45
108
46
109
private Size FullSizeWithChildren ( BreedingTreeNodeViewModel node )
47
110
{
48
- var childrenByDepth = node . Value . TraversedTopDown ( 0 ) . GroupBy ( p => p . Item2 ) . ToDictionary ( g => g . Key , g => g . Select ( p => p . Item1 ) . ToList ( ) ) ;
111
+ if ( _fullSizes . ContainsKey ( node ) ) return _fullSizes [ node ] ;
49
112
50
- var maxWidthByDepth = childrenByDepth . ToDictionary ( kvp => kvp . Key , kvp => kvp . Value . Max ( n => _sizes [ VisitedGraph . NodeFor ( n ) ] . Width ) ) ;
51
- var minHeightByDepth = childrenByDepth . ToDictionary (
52
- kvp => kvp . Key ,
53
- kvp => Parameters . VertexGap * ( kvp . Value . Count - 1 ) + kvp . Value . Sum ( n => _sizes [ VisitedGraph . NodeFor ( n ) ] . Height )
54
- ) ;
113
+ if ( ! node . Value . Children . Any ( ) )
114
+ {
115
+ var size = _sizes [ node ] ;
116
+ _fullSizes [ node ] = size ;
117
+ return size ;
118
+ }
55
119
56
- var fullWidth = ( childrenByDepth . Count - 1 ) * Parameters . LayerGap + maxWidthByDepth . Values . Sum ( ) ;
57
- var fullHeight = minHeightByDepth . Values . Max ( ) ;
120
+ Size fullSize = new Size (
121
+ width : node . Value . Children . Max ( n => FullSizeWithChildren ( _viewmodels [ n ] ) . Width ) + Parameters . LayerGap + _sizes [ node ] . Width ,
122
+ height : Math . Max ( node . Value . Children . Sum ( c => FullSizeWithChildren ( _viewmodels [ c ] ) . Height ) + Parameters . VertexGap , _sizes [ node ] . Height )
123
+ ) ;
58
124
59
- return new Size ( fullWidth , fullHeight ) ;
125
+ _fullSizes . Add ( node , fullSize ) ;
126
+ return fullSize ;
60
127
}
61
128
62
129
protected override void InternalCompute ( )
@@ -66,72 +133,83 @@ protected override void InternalCompute()
66
133
. ToDictionary ( g => g . Key , g => g . Select ( p => VisitedGraph . NodeFor ( p . Item1 ) ) . ToList ( ) ) ;
67
134
68
135
var fullSize = FullSizeWithChildren ( VisitedGraph . NodeFor ( VisitedGraph . Tree . Root ) ) ;
69
- var layerX = fullSize . Width / 2 ;
136
+ var layerCenterX = fullSize . Width / 2 ;
70
137
138
+ // node positions are centered within the node
71
139
// start from root node, center-right
140
+ double prevWidth = 0 ;
72
141
foreach ( var kvp in orderedNodesByDepth . OrderBy ( kvp => kvp . Key ) )
73
142
{
74
- layerX -= kvp . Value . Max ( n => _sizes [ n ] . Width ) ;
75
- layerX -= Parameters . LayerGap ;
76
-
77
143
var depth = kvp . Key ;
78
- foreach ( var node in kvp . Value )
144
+ var width = kvp . Value . Max ( n => _sizes [ n ] . Width ) ;
145
+
146
+ if ( depth == 0 )
147
+ {
148
+ layerCenterX -= width / 2 ; // properly align right-most (root) node with right side of tree
149
+ }
150
+ else
79
151
{
152
+ layerCenterX -= prevWidth / 2 ;
153
+ layerCenterX -= Parameters . LayerGap ;
154
+ layerCenterX -= width / 2 ;
155
+ }
156
+
157
+ foreach ( var vmNode in kvp . Value )
158
+ {
159
+ var node = _nodesByVm [ vmNode ] ;
160
+
80
161
if ( depth == 0 )
81
162
{
82
- VertexPositions [ node ] = new Point ( layerX , 0 ) ;
163
+ VertexPositions [ vmNode ] = new Point ( layerCenterX , 0 ) ;
83
164
continue ;
84
165
}
85
166
86
- var parentNode = orderedNodesByDepth [ depth - 1 ] . Single ( p => p . Value . Children . Contains ( node . Value ) ) ;
167
+ // all of these nodes (depth > 0) will have a parent and a sibling
87
168
88
- var parentHeight = _sizes [ parentNode ] . Height ;
89
- var parentPos = VertexPositions [ parentNode ] ;
90
- parentPos . Y += parentHeight / 2 ;
169
+ // self Y will be the center of child Ys.
170
+ // child Ys are based on their full height / 2
91
171
92
- var selfTotalHeight = FullSizeWithChildren ( node ) . Height ;
93
- var parentTotalHeight = FullSizeWithChildren ( parentNode ) . Height ;
94
-
172
+ // ('Y' in this comment block refers to top of node)
173
+ // parent Y will be avg(child1y [top], child2y [bottom])
174
+ // child1y = parentFullTopY + child1FullHeight / 2
175
+ // child2y = parentFullBottomY - child2FullHeight / 2
95
176
96
- bool isFirstChild = parentNode . Value . Children . First ( ) == node . Value ;
177
+ var parentVm = orderedNodesByDepth [ depth - 1 ] . Single ( p => p . Value . Children . Contains ( vmNode . Value ) ) ;
178
+ var parentNode = _nodesByVm [ parentVm ] ;
97
179
98
- var selfY = isFirstChild
99
- ? parentPos . Y - parentTotalHeight / 2
100
- : parentPos . Y + Parameters . VertexGap ;
180
+ bool isFirstChild = parentVm . Value . Children . First ( ) == vmNode . Value ;
181
+ double nodeCenterY ;
182
+ if ( isFirstChild )
183
+ {
184
+ nodeCenterY = parentNode . FullTopY + node . FullSize . Height / 2 ;
185
+ }
186
+ else
187
+ {
188
+ nodeCenterY = parentNode . FullBottomY - node . FullSize . Height / 2 ;
189
+ }
101
190
102
- VertexPositions [ node ] = new Point ( layerX , selfY ) ;
191
+ node . SelfCenter = new Point ( layerCenterX , nodeCenterY ) ;
103
192
}
193
+
194
+ prevWidth = width ;
104
195
}
105
196
106
197
// current positions are roughly accurate, but center each parent within their children
107
198
foreach ( var depth in orderedNodesByDepth . Keys . OrderByDescending ( d => d ) )
108
199
{
109
- foreach ( var node in orderedNodesByDepth [ depth ] )
200
+ foreach ( var nodeVm in orderedNodesByDepth [ depth ] )
110
201
{
111
- if ( node . Value . Children . Any ( ) )
202
+ if ( nodeVm . Value . Children . Any ( ) )
112
203
{
113
- var parent1 = VisitedGraph . NodeFor ( node . Value . Children . First ( ) ) ;
114
- var parent2 = VisitedGraph . NodeFor ( node . Value . Children . Last ( ) ) ;
115
-
116
- var parent1Pos = VertexPositions [ parent1 ] ;
117
- var parent2Pos = VertexPositions [ parent2 ] ;
118
-
119
- var parent1Center = new Point (
120
- parent1Pos . X + _sizes [ parent1 ] . Width / 2 ,
121
- parent1Pos . Y + _sizes [ parent1 ] . Height / 2
122
- ) ;
204
+ var node = _nodesByVm [ nodeVm ] ;
123
205
124
- var parent2Center = new Point (
125
- parent2Pos . X + _sizes [ parent2 ] . Width / 2 ,
126
- parent2Pos . Y + _sizes [ parent2 ] . Height / 2
127
- ) ;
206
+ var parent1 = VisitedGraph . NodeFor ( nodeVm . Value . Children . First ( ) ) ;
207
+ var parent2 = VisitedGraph . NodeFor ( nodeVm . Value . Children . Last ( ) ) ;
128
208
129
- var newPos = new Point (
130
- VertexPositions [ node ] . X ,
131
- ( parent1Center . Y + parent2Center . Y ) / 2 - _sizes [ node ] . Height / 2
132
- ) ;
209
+ var p1Node = _nodesByVm [ parent1 ] ;
210
+ var p2Node = _nodesByVm [ parent2 ] ;
133
211
134
- VertexPositions [ node ] = newPos ;
212
+ node . SelfCenter = new Point ( node . SelfCenter . X , ( p1Node . SelfBottomY + p2Node . SelfTopY ) / 2 ) ;
135
213
}
136
214
}
137
215
}
0 commit comments