/// <summary> /// Apply the appropriate layout to the specified cluster and its children (bottom up) /// </summary> /// <param name="cluster">the root of the cluster hierarchy to lay out</param> /// <returns>list of edges external to the cluster</returns> void LayoutCluster(Cluster cluster) { if (cluster.IsCollapsed) return; LayoutAlgorithmSettings settings = clusterSettings(cluster); cluster.UnsetInitialLayoutState(); if (runInParallel && cluster.Clusters.Count() > 1) Parallel.ForEach(cluster.Clusters, parallelOptions, LayoutCluster); else foreach (var cl in cluster.Clusters) LayoutCluster(cl); List<GeometryGraph> components = (List<GeometryGraph>) GetComponents(cluster); //currentComponentFraction = (1.0 / clusterCount) / components.Count; // if (runInParallel) // Parallel.ForEach(components, parallelOptions, comp => LayoutComponent(settings, comp)); // else // debug!!!!!! components.ForEach(c => LayoutComponent(settings, c)); var bounds = MdsGraphLayout.PackGraphs(components, settings); foreach (var g in components) FixOriginalGraph(g, true); cluster.UpdateBoundary(bounds); cluster.SetInitialLayoutState(settings.ClusterMargin); cluster.RaiseLayoutDoneEvent(); // var l = new List<DebugCurve>(); // foreach (var node in cluster.Nodes) { // l.Add(new DebugCurve(node.BoundaryCurve)); // } // foreach (var cl in cluster.AllClustersDepthFirstExcludingSelf()) { // l.Add(new DebugCurve(cl.BoundaryCurve)); // l.AddRange(cl.Nodes.Select(n=>new DebugCurve(n.BoundaryCurve))); // } // LayoutAlgorithmSettings.ShowDebugCurves(l.ToArray()); }
/// <summary> /// Apply the appropriate layout to the specified cluster /// </summary> /// <param name="cluster">the root of the cluster hierarchy to lay out</param> /// <returns>list of edges external to the cluster</returns> void LayoutCluster(Cluster cluster) { ProgressStep(); cluster.UnsetInitialLayoutState(); FastIncrementalLayoutSettings settings = null; LayoutAlgorithmSettings s = clusterSettings(cluster); Directions layoutDirection = Directions.None; if (s is SugiyamaLayoutSettings) { var ss = s as SugiyamaLayoutSettings; settings = ss.FallbackLayoutSettings != null ? new FastIncrementalLayoutSettings((FastIncrementalLayoutSettings) ss.FallbackLayoutSettings) : new FastIncrementalLayoutSettings(); layoutDirection = LayeredLayoutEngine.GetLayoutDirection(ss); } else { settings = new FastIncrementalLayoutSettings((FastIncrementalLayoutSettings) s); } settings.ApplyForces = true; settings.MinorIterations = 10; settings.AvoidOverlaps = true; settings.InterComponentForces = false; settings.IdealEdgeLength = new IdealEdgeLengthSettings { EdgeDirectionConstraints = layoutDirection, ConstrainedEdgeSeparation = 30 }; settings.EdgeRoutingSettings.EdgeRoutingMode = EdgeRoutingMode.Spline; HashSet<Node> addedNodes; if (addedNodesByCluster.TryGetValue(cluster, out addedNodes)) { // if the structure of the cluster has changed then we apply unconstrained layout first, // then introduce structural constraints, and then all constraints settings.MinConstraintLevel = 0; settings.MaxConstraintLevel = 2; } else settings.MinConstraintLevel = 2; GeometryGraph newGraph = GetShallowCopyGraphUnderCluster(cluster); LayoutAlgorithmHelpers.ComputeDesiredEdgeLengths(settings.IdealEdgeLength, newGraph); // orthogonal ordering constraints preserve the left-of, above-of relationships between existing nodes // (we do not apply these to the newly added nodes) GenerateOrthogonalOrderingConstraints( newGraph.Nodes.Where(v => !addedNodes.Contains(v.UserData as Node)).ToList(), settings); LayoutComponent(newGraph, settings); //LayoutAlgorithmSettings.ShowGraph(newGraph); InitialLayoutByCluster.FixOriginalGraph(newGraph, true); cluster.UpdateBoundary(newGraph.BoundingBox); }