18 changed files with 344 additions and 492 deletions
@ -1,21 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
|
|
||||||
namespace Debugger.AddIn.Visualizers.Graph.Layout |
|
||||||
{ |
|
||||||
// TODO this class is almost not necessary, is used only for TreeLayouter purposes.
|
|
||||||
// TreeLayouter could remember the additional information in a Dictionary PositionedEdge -> bool
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Edge in the tree-layouted <see cref="PositionedGraph"/>.
|
|
||||||
/// </summary>
|
|
||||||
public class TreeGraphEdge : PositionedEdge |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Is this an edges making up the main tree?
|
|
||||||
/// </summary>
|
|
||||||
public bool IsTreeEdge { get; set; } |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,75 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using Debugger.AddIn.Visualizers.Graph.Drawing; |
|
||||||
|
|
||||||
namespace Debugger.AddIn.Visualizers.Graph.Layout |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Node in tree-layouted <see cref="PositionedGraph"/>.
|
|
||||||
/// This is the abstract ancestor of TreeNodeLR and TreeNodeTB.
|
|
||||||
/// There are 2 dimensions - "main" and "lateral".
|
|
||||||
/// Main dimension is the dimension in which the graph depth grows (vertical when TB, horizontal when LR).
|
|
||||||
/// Lateral dimension is the other dimension. Siblings are placed next to each other in Lateral dimension.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class TreeGraphNode : PositionedGraphNode |
|
||||||
{ |
|
||||||
public static TreeGraphNode Create(LayoutDirection direction, ObjectGraphNode objectNode) |
|
||||||
{ |
|
||||||
switch (direction) { |
|
||||||
case LayoutDirection.TopBottom: return new TreeNodeTB(objectNode); |
|
||||||
case LayoutDirection.LeftRight: return new TreeNodeLR(objectNode); |
|
||||||
default: throw new DebuggerVisualizerException("Unsupported layout direction: " + direction.ToString()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public double HorizontalMargin { get; set; } |
|
||||||
public double VerticalMargin { get; set; } |
|
||||||
|
|
||||||
protected TreeGraphNode(ObjectGraphNode objectNode) : base(objectNode) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Width or height of the subtree.
|
|
||||||
/// </summary>
|
|
||||||
public double SubtreeSize { get; set; } |
|
||||||
|
|
||||||
public abstract double MainCoord { get; set; } |
|
||||||
public abstract double LateralCoord { get; set; } |
|
||||||
|
|
||||||
public abstract double MainSize { get; } |
|
||||||
public abstract double LateralSize { get; } |
|
||||||
|
|
||||||
public double MainSizeWithMargin { get { return MainSize + MainMargin; } } |
|
||||||
public double LateralSizeWithMargin { get { return LateralSize + LateralMargin; } } |
|
||||||
|
|
||||||
public abstract double MainMargin { get; } |
|
||||||
public abstract double LateralMargin { get; } |
|
||||||
|
|
||||||
public IEnumerable<PositionedEdge> ChildEdges |
|
||||||
{ |
|
||||||
get |
|
||||||
{ |
|
||||||
foreach (TreeGraphEdge childEdge in Edges) |
|
||||||
{ |
|
||||||
if (childEdge.IsTreeEdge) |
|
||||||
{ |
|
||||||
yield return childEdge; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public IEnumerable<TreeGraphNode> Childs |
|
||||||
{ |
|
||||||
get |
|
||||||
{ |
|
||||||
foreach (PositionedEdge outEdge in this.ChildEdges) |
|
||||||
yield return (TreeGraphNode)outEdge.Target; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,27 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using Debugger.AddIn.Visualizers.Graph.Drawing; |
|
||||||
|
|
||||||
namespace Debugger.AddIn.Visualizers.Graph.Layout |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// TreeNode used in LR layout mode.
|
|
||||||
/// </summary>
|
|
||||||
public class TreeNodeLR: TreeGraphNode |
|
||||||
{ |
|
||||||
public TreeNodeLR(ObjectGraphNode objectNode) : base(objectNode) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public override double MainSize { get { return this.Width; } } |
|
||||||
public override double LateralSize { get { return this.Height ; } } |
|
||||||
|
|
||||||
public override double MainCoord { get { return this.Left; } set { this.Left = value; } } |
|
||||||
public override double LateralCoord { get { return this.Top; } set { this.Top = value; } } |
|
||||||
|
|
||||||
public override double MainMargin { get { return this.HorizontalMargin; } } |
|
||||||
public override double LateralMargin { get { return this.VerticalMargin; } } |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,27 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using Debugger.AddIn.Visualizers.Graph.Drawing; |
|
||||||
|
|
||||||
namespace Debugger.AddIn.Visualizers.Graph.Layout |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// TreeNode used in TB layout mode.
|
|
||||||
/// </summary>
|
|
||||||
public class TreeNodeTB : TreeGraphNode |
|
||||||
{ |
|
||||||
public TreeNodeTB(ObjectGraphNode objectNode) : base(objectNode) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
public override double MainSize { get { return this.Height; } } |
|
||||||
public override double LateralSize { get { return this.Width; } } |
|
||||||
|
|
||||||
public override double MainCoord { get { return this.Top; } set { this.Top = value; } } |
|
||||||
public override double LateralCoord { get { return this.Left; } set { this.Left = value; } } |
|
||||||
|
|
||||||
public override double MainMargin { get { return this.VerticalMargin; } } |
|
||||||
public override double LateralMargin { get { return this.HorizontalMargin; } } |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,187 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Windows; |
||||||
|
using Debugger.AddIn.Visualizers.Graph.Drawing; |
||||||
|
using System.Linq; |
||||||
|
|
||||||
|
namespace Debugger.AddIn.Visualizers.Graph.Layout |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Calculates layout of <see cref="ObjectGraph" />, producing <see cref="PositionedGraph" />.
|
||||||
|
/// </summary>
|
||||||
|
public class TreeLayout |
||||||
|
{ |
||||||
|
private static readonly double NodeMarginH = 30; |
||||||
|
private static readonly double NodeMarginV = 30; |
||||||
|
|
||||||
|
GraphEdgeRouter edgeRouter = new GraphEdgeRouter(); |
||||||
|
/// <summary>
|
||||||
|
/// The produced layout is either a horizontal or vertical tree.
|
||||||
|
/// </summary>
|
||||||
|
public LayoutDirection LayoutDirection { get; private set; } |
||||||
|
|
||||||
|
public TreeLayout(LayoutDirection layoutDirection) |
||||||
|
{ |
||||||
|
this.LayoutDirection = layoutDirection; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates layout for given <see cref="ObjectGraph" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectGraph"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public PositionedGraph CalculateLayout(ObjectGraph objectGraph, Expanded expanded) |
||||||
|
{ |
||||||
|
var positionedGraph = BuildPositionedGraph(objectGraph, expanded); |
||||||
|
CalculateLayout(positionedGraph); |
||||||
|
this.edgeRouter.RouteEdges(positionedGraph); |
||||||
|
|
||||||
|
return positionedGraph; |
||||||
|
} |
||||||
|
|
||||||
|
// Expanded is passed so that the correct ContentNodes are expanded in the PositionedNode
|
||||||
|
PositionedGraph BuildPositionedGraph(ObjectGraph objectGraph, Expanded expanded) |
||||||
|
{ |
||||||
|
var positionedNodeFor = new Dictionary<ObjectGraphNode, PositionedNode>(); |
||||||
|
var positionedGraph = new PositionedGraph(); |
||||||
|
|
||||||
|
// create empty PositionedNodes
|
||||||
|
foreach (ObjectGraphNode objectNode in objectGraph.ReachableNodes) { |
||||||
|
var posNode = new PositionedNode(objectNode); |
||||||
|
posNode.InitContentFromObjectNode(expanded); |
||||||
|
positionedGraph.AddNode(posNode); |
||||||
|
positionedNodeFor[objectNode] = posNode; |
||||||
|
} |
||||||
|
|
||||||
|
// create edges
|
||||||
|
foreach (PositionedNode posNode in positionedGraph.Nodes) |
||||||
|
{ |
||||||
|
foreach (PositionedNodeProperty property in posNode.Properties) { |
||||||
|
if (property.ObjectGraphProperty.TargetNode != null) { |
||||||
|
ObjectGraphNode targetObjectNode = property.ObjectGraphProperty.TargetNode; |
||||||
|
PositionedNode edgeTarget = positionedNodeFor[targetObjectNode]; |
||||||
|
property.Edge = new PositionedEdge { |
||||||
|
Name = property.Name, Source = property, Target = edgeTarget |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
positionedGraph.Root = positionedNodeFor[objectGraph.Root]; |
||||||
|
return positionedGraph; |
||||||
|
} |
||||||
|
|
||||||
|
void CalculateLayout(PositionedGraph positionedGraph) |
||||||
|
{ |
||||||
|
HashSet<PositionedNode> seenNodes = new HashSet<PositionedNode>(); |
||||||
|
HashSet<PositionedEdge> treeEdges = new HashSet<PositionedEdge>(); |
||||||
|
// first layout pass
|
||||||
|
CalculateSubtreeSizes(positionedGraph.Root, seenNodes, treeEdges); |
||||||
|
// second layout pass
|
||||||
|
CalculateNodePosRecursive(positionedGraph.Root, treeEdges, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
// determines which edges are tree edges, and calculates subtree size for each node
|
||||||
|
private void CalculateSubtreeSizes(PositionedNode root, HashSet<PositionedNode> seenNodes, HashSet<PositionedEdge> treeEdges) |
||||||
|
{ |
||||||
|
seenNodes.Add(root); |
||||||
|
double subtreeSize = 0; |
||||||
|
foreach (var property in root.Properties) { |
||||||
|
var edge = property.Edge; |
||||||
|
if (edge != null) { |
||||||
|
var targetNode = edge.Target; |
||||||
|
if (!seenNodes.Contains(targetNode)) { |
||||||
|
// when we come to a node for the first time, we declare the incoming edge a tree edge
|
||||||
|
treeEdges.Add(edge); |
||||||
|
CalculateSubtreeSizes(targetNode, seenNodes, treeEdges); |
||||||
|
subtreeSize += targetNode.SubtreeSize; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
root.Measure(); |
||||||
|
root.SubtreeSize = Math.Max(GetLateralSizeWithMargin(root), subtreeSize); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Given SubtreeSize for each node, positions the nodes, in a left-to-right or top-to-bottom layout.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node"></param>
|
||||||
|
/// <param name="lateralStart"></param>
|
||||||
|
/// <param name="mainStart"></param>
|
||||||
|
void CalculateNodePosRecursive(PositionedNode node, HashSet<PositionedEdge> treeEdges, double lateralBase, double mainBase) |
||||||
|
{ |
||||||
|
double childsSubtreeSize = TreeChildNodes(node, treeEdges).Sum(child => child.SubtreeSize); |
||||||
|
double center = TreeEdges(node, treeEdges).Count() == 0 ? 0 : 0.5 * (childsSubtreeSize - (GetLateralSizeWithMargin(node))); |
||||||
|
if (center < 0) { |
||||||
|
// if root is larger than subtree, it would be shifted below lateralStart
|
||||||
|
// -> make whole layout start at lateralStart
|
||||||
|
lateralBase -= center; |
||||||
|
} |
||||||
|
|
||||||
|
SetLateral(node, GetLateral(node) + lateralBase + center); |
||||||
|
SetMain(node, mainBase); |
||||||
|
|
||||||
|
double childLateral = lateralBase; |
||||||
|
double childsMainFixed = GetMain(node) + GetMainSizeWithMargin(node); |
||||||
|
foreach (var child in TreeChildNodes(node, treeEdges)) { |
||||||
|
CalculateNodePosRecursive(child, treeEdges, childLateral, childsMainFixed); |
||||||
|
childLateral += child.SubtreeSize; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
IEnumerable<PositionedEdge> TreeEdges(PositionedNode node, HashSet<PositionedEdge> treeEdges) |
||||||
|
{ |
||||||
|
return node.Edges.Where(e => treeEdges.Contains(e)); |
||||||
|
} |
||||||
|
|
||||||
|
IEnumerable<PositionedNode> TreeChildNodes(PositionedNode node, HashSet<PositionedEdge> treeEdges) |
||||||
|
{ |
||||||
|
return TreeEdges(node, treeEdges).Select(e => e.Target); |
||||||
|
} |
||||||
|
|
||||||
|
#region Horizontal / vertical layout helpers
|
||||||
|
|
||||||
|
double GetMainSizeWithMargin(PositionedNode node) |
||||||
|
{ |
||||||
|
return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Width + NodeMarginH : node.Height + NodeMarginV; |
||||||
|
} |
||||||
|
|
||||||
|
double GetLateralSizeWithMargin(PositionedNode node) |
||||||
|
{ |
||||||
|
return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Height + NodeMarginV : node.Width + NodeMarginH; |
||||||
|
} |
||||||
|
|
||||||
|
double GetMain(PositionedNode node) |
||||||
|
{ |
||||||
|
return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Left : node.Top; |
||||||
|
} |
||||||
|
|
||||||
|
double GetLateral(PositionedNode node) |
||||||
|
{ |
||||||
|
return (this.LayoutDirection == LayoutDirection.LeftRight) ? node.Top : node.Left; |
||||||
|
} |
||||||
|
|
||||||
|
void SetMain(PositionedNode node, double value) |
||||||
|
{ |
||||||
|
if (this.LayoutDirection == LayoutDirection.LeftRight) { |
||||||
|
node.Left = value; |
||||||
|
} else { |
||||||
|
node.Top = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void SetLateral(PositionedNode node, double value) |
||||||
|
{ |
||||||
|
if (this.LayoutDirection == LayoutDirection.LeftRight) { |
||||||
|
node.Top = value; |
||||||
|
} else { |
||||||
|
node.Left = value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endregion
|
||||||
|
} |
||||||
|
} |
||||||
@ -1,137 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Collections.Generic; |
|
||||||
using System.Windows; |
|
||||||
using Debugger.AddIn.Visualizers.Graph.Drawing; |
|
||||||
using System.Linq; |
|
||||||
|
|
||||||
namespace Debugger.AddIn.Visualizers.Graph.Layout |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Calculates layout of <see cref="ObjectGraph" />, producing <see cref="PositionedGraph" />.
|
|
||||||
/// </summary>
|
|
||||||
public class TreeLayouter |
|
||||||
{ |
|
||||||
private static readonly double horizNodeMargin = 30; |
|
||||||
private static readonly double vertNodeMargin = 30; |
|
||||||
|
|
||||||
GraphEdgeRouter edgeRouter = new GraphEdgeRouter(); |
|
||||||
|
|
||||||
public TreeLayouter() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calculates layout for given <see cref="ObjectGraph" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="objectGraph"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public PositionedGraph CalculateLayout(ObjectGraph objectGraph, LayoutDirection direction, Expanded expanded) |
|
||||||
{ |
|
||||||
var positionedGraph = BuildPositionedGraph(objectGraph, direction, expanded); |
|
||||||
CalculateLayout(positionedGraph); |
|
||||||
this.edgeRouter.RouteEdges(positionedGraph); |
|
||||||
|
|
||||||
return positionedGraph; |
|
||||||
} |
|
||||||
|
|
||||||
PositionedGraph BuildPositionedGraph(ObjectGraph objectGraph, LayoutDirection direction, Expanded expanded)// Expanded is passed so that the correct ContentNodes are expanded in the PositionedNode
|
|
||||||
{ |
|
||||||
var treeNodeFor = new Dictionary<ObjectGraphNode, PositionedGraphNode>(); |
|
||||||
var resultGraph = new PositionedGraph(); |
|
||||||
|
|
||||||
// create empty PositionedNodes
|
|
||||||
foreach (ObjectGraphNode objectGraphNode in objectGraph.ReachableNodes) { |
|
||||||
TreeGraphNode posNode = TreeGraphNode.Create(direction, objectGraphNode); |
|
||||||
posNode.InitContentFromObjectNode(expanded); |
|
||||||
posNode.HorizontalMargin = horizNodeMargin; |
|
||||||
posNode.VerticalMargin = vertNodeMargin; |
|
||||||
resultGraph.AddNode(posNode); |
|
||||||
treeNodeFor[objectGraphNode] = posNode; |
|
||||||
} |
|
||||||
|
|
||||||
// create edges
|
|
||||||
foreach (PositionedGraphNode posNode in resultGraph.Nodes) |
|
||||||
{ |
|
||||||
foreach (PositionedNodeProperty property in posNode.Properties) { |
|
||||||
if (property.ObjectGraphProperty.TargetNode != null) { |
|
||||||
ObjectGraphNode targetObjectNode = property.ObjectGraphProperty.TargetNode; |
|
||||||
PositionedGraphNode edgeTarget = treeNodeFor[targetObjectNode]; |
|
||||||
property.Edge = new TreeGraphEdge |
|
||||||
{ IsTreeEdge = false, Name = property.Name, Source = property, Target = edgeTarget }; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
resultGraph.Root = treeNodeFor[objectGraph.Root]; |
|
||||||
return resultGraph; |
|
||||||
} |
|
||||||
|
|
||||||
void CalculateLayout(PositionedGraph resultGraph) |
|
||||||
{ |
|
||||||
HashSet<PositionedGraphNode> seenNodes = new HashSet<PositionedGraphNode>(); |
|
||||||
// first layout pass
|
|
||||||
CalculateSubtreeSizes((TreeGraphNode)resultGraph.Root, seenNodes); |
|
||||||
// second layout pass
|
|
||||||
CalculateNodePosRecursive((TreeGraphNode)resultGraph.Root, 0, 0); |
|
||||||
} |
|
||||||
|
|
||||||
// determines which edges are tree edges, and calculates subtree size for each node
|
|
||||||
private void CalculateSubtreeSizes(TreeGraphNode root, HashSet<PositionedGraphNode> seenNodes) |
|
||||||
{ |
|
||||||
seenNodes.Add(root); |
|
||||||
double subtreeSize = 0; |
|
||||||
|
|
||||||
foreach (PositionedNodeProperty property in root.Properties) { |
|
||||||
var edge = property.Edge as TreeGraphEdge; // we know that these egdes are TreeEdges
|
|
||||||
if (edge != null) { |
|
||||||
var neigborNode = (TreeGraphNode)edge.Target; |
|
||||||
if (seenNodes.Contains(neigborNode)) { |
|
||||||
edge.IsTreeEdge = false; |
|
||||||
} else { |
|
||||||
edge.IsTreeEdge = true; |
|
||||||
CalculateSubtreeSizes(neigborNode, seenNodes); |
|
||||||
subtreeSize += neigborNode.SubtreeSize; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
root.Measure(); |
|
||||||
root.SubtreeSize = Math.Max(root.LateralSizeWithMargin, subtreeSize); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Given SubtreeSize for each node, positions the nodes, in a left-to-right or top-to-bottom fashion.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="node"></param>
|
|
||||||
/// <param name="lateralStart"></param>
|
|
||||||
/// <param name="mainStart"></param>
|
|
||||||
private void CalculateNodePosRecursive(TreeGraphNode node, double lateralStart, double mainStart) |
|
||||||
{ |
|
||||||
double childsSubtreeSize = node.Childs.Sum(child => child.SubtreeSize); |
|
||||||
// center this node
|
|
||||||
double center = node.ChildEdges.Count() == 0 ? 0 : 0.5 * (childsSubtreeSize - (node.LateralSizeWithMargin)); |
|
||||||
if (center < 0) { |
|
||||||
// if root is larger than subtree, it would be shifted below lateralStart
|
|
||||||
// -> make whole layout start at lateralStart
|
|
||||||
lateralStart -= center; |
|
||||||
} |
|
||||||
|
|
||||||
// design alternatives
|
|
||||||
// node.MainPos += center; // used this
|
|
||||||
// Adapt(node).PosLateral += center; // TreeNodeAdapterLR + TreeNodeAdapterTB
|
|
||||||
// SetMainPos(node, GetMainPos(node) + 10) // TreeNodeAdapterLR + TreeNodeAdapterTB, no creation
|
|
||||||
|
|
||||||
node.LateralCoord += lateralStart + center; |
|
||||||
node.MainCoord = mainStart; |
|
||||||
|
|
||||||
double childLateral = lateralStart; |
|
||||||
double childsMainFixed = node.MainCoord + node.MainSizeWithMargin; |
|
||||||
foreach (TreeGraphNode child in node.Childs) { |
|
||||||
CalculateNodePosRecursive(child, childLateral, childsMainFixed); |
|
||||||
childLateral += child.SubtreeSize; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
Loading…
Reference in new issue