public void RefineLayout(int iterations)
{
// Prepare state for algorithm.
BidirectionalGraph<string, IEdge<string>> graph
= new BidirectionalGraph<string, IEdge<string>>(false);
Dictionary<string, Point> positions
= new Dictionary<string, Point>();
// Anything to do?
if (BayesianNetwork.VariablesOrdered.Any() == false)
{
this.Positions = new Dictionary<string, Point>();
IterationCount += iterations;
return;
}
Random random = new Random(0);
foreach (var rv in BayesianNetwork.VariablesOrdered)
{
graph.AddVertex(rv.Name);
foreach (var child
in rv.Children.Select(c => BayesianNetwork.GetVariable(c)))
{
graph.AddVertex(child.Name);
graph.AddEdge(new Edge<string>(rv.Name, child.Name));
}
// If we have no existing layout yet, lets try to prime the
// alg by putting pure parents at top and pure children at
// bottom.
if (Positions.Count != 0)
{
// We have existing layout. Start with it but add slight
// randomness.
Point positionNoised;
if (Positions.ContainsKey(rv.Name))
{
positionNoised = Positions[rv.Name];
}
else
{
positionNoised = new Point();
}
positionNoised.X += (random.NextDouble() - 0.5) * 0.01;
positionNoised.Y += (random.NextDouble() - 0.5) * 0.01;
positions[rv.Name] = positionNoised;
}
}
// Initialize algorithm.
var layoutAlgorithms
= new StandardLayoutAlgorithmFactory<string, IEdge<string>, IBidirectionalGraph<string, IEdge<string>>>();
var layoutContext = new LayoutContext<string, IEdge<string>, IBidirectionalGraph<string, IEdge<string>>>(
graph,
positions,
_sizes,
LayoutMode.Simple);
ILayoutAlgorithm<string, IEdge<string>, IBidirectionalGraph<string, IEdge<string>>> layoutAlgorithm;
var algorithm = this._options.Algorithm;
// Hack: SugiyamaEfficient breaks if no edges.
if (algorithm == NetworkLayoutOptions.AlgorithmEnum.KK || graph.Edges.Count() == 0)
{
var layoutParameters = new KKLayoutParameters();
layoutParameters.Height = 1000;
layoutParameters.Width = 1000;
layoutParameters.MaxIterations = iterations;
layoutParameters.LengthFactor = 1.35;
layoutParameters.K *= 10.1;
layoutParameters.AdjustForGravity = false;
layoutAlgorithm = layoutAlgorithms.CreateAlgorithm("KK", layoutContext, layoutParameters);
}
else if (algorithm == NetworkLayoutOptions.AlgorithmEnum.SugiyamaEfficient)
{
var layoutParameters = new EfficientSugiyamaLayoutParameters();
layoutParameters.MinimizeEdgeLength = true;
layoutParameters.OptimizeWidth = true;
layoutParameters.WidthPerHeight = 1.65;
layoutParameters.VertexDistance = this._options.NodeSeparationTarget;
layoutParameters.LayerDistance = 5.0;
layoutAlgorithm = layoutAlgorithms.CreateAlgorithm("EfficientSugiyama", layoutContext, layoutParameters);
}
else if (algorithm == NetworkLayoutOptions.AlgorithmEnum.Sugiyama)
{
var layoutParameters = new SugiyamaLayoutParameters();
layoutParameters.MaxWidth = 1024;
layoutParameters.VerticalGap = 1.0f;
layoutParameters.DirtyRound = true;
layoutAlgorithm = layoutAlgorithms.CreateAlgorithm("Sugiyama", layoutContext, layoutParameters);
}
else if (algorithm == NetworkLayoutOptions.AlgorithmEnum.CompoundFDP)
{
var layoutParameters = new CompoundFDPLayoutParameters();
layoutParameters.GravitationFactor = 0.8;
layoutParameters.IdealEdgeLength = 30;
layoutParameters.RepulsionConstant = 300;
layoutAlgorithm = layoutAlgorithms.CreateAlgorithm("CompoundFDP", layoutContext, layoutParameters);
}
else
{
throw new InvalidOperationException("Unknown layout.");
}
// Compute.
layoutAlgorithm.Compute();
// Store Results.
this.Positions
= layoutAlgorithm.VertexPositions.ToDictionary(
(kvp) => kvp.Key,
(kvp) => kvp.Value
);
// Done.
IterationCount += iterations;
}