/// <summary> /// Initializes a new instance of the PathFinder class. /// Path-finding will depend on the direction of arrows. /// </summary> /// <param name="diagram">A FlowChart instance in which to look for paths or cycles.</param> public PathFinder(FlowChart diagram) { graph = new FCGraph(diagram, false); ignoreDirection = false; }
/// <summary> /// Initializes a new instance of the PathFinder class. /// </summary> /// <param name="diagram">A FlowChart instance in which to look for paths or cycles.</param> /// <param name="ignoreDirection">Specifies whether the direction of arrows /// should be considered when looking for paths or cycles.</param> public PathFinder(FlowChart diagram, bool ignoreDirection) { graph = new FCGraph(diagram, false, ignoreDirection); this.ignoreDirection = ignoreDirection; }
public virtual bool Arrange(FlowChart chart) { chart.UndoManager.onStartLayout("Anneal layout"); // Build the graph FCGraph graph = new FCGraph(chart, _keepGroupLayout); // Find the root adapter Layout.INode rootNode = null; if (_root != null) { foreach (FCNode node in graph.Nodes) { if (node.Node == _root) { rootNode = node; break; } } } // Split graph to subgraphs Layout.IGraph[] subgraphs = null; if (_splitGraph) { subgraphs = Layout.GraphSplitter.Split( graph, new FCGraphBuilder(chart, false)); } else { subgraphs = new Layout.IGraph[] { graph }; } // Create the layouter Layout.AnnealLayout layout = new Layout.AnnealLayout(); Layout.LayoutProgress progress = null; if (_progress != null) progress = new Layout.LayoutProgress(this.OnLayoutProgress); Layout.AnnealLayoutInfo info = new Layout.AnnealLayoutInfo(); info.DistributionFactor = this.DistributionFactor; info.BoundaryFactor = this.BoundaryFactor; info.EdgeLengthFactor = this.ArrowLengthFactor; info.CrossingEdgesCost = this.CrossingArrowsCost; info.NodeEdgeDistFactor = this.NodeArrowDistFactor; info.IterationsPerStage = this.IterationsPerStage; info.Stages = this.Stages; info.Temperature = this.InitialTemperature; info.TemperatureScale = this.TemperatureScale; info.LayoutArea = this.LayoutArea; info.WidthHeightRatio = this.WidthHeightRatio; info.Randomize = this.Randomize; float xOffset = 0; foreach (FCGraph subgraph in subgraphs) { // If a root node is specified and the subgraph // does not contain that node, do not arrange // the subgraph if (rootNode != null) { if (!subgraph.Nodes.Contains(rootNode)) continue; } layout.Arrange(subgraph, info, progress); // Translate the whole subgraph RectangleF graphBounds = subgraph.GetBounds(false); float xToMove = xOffset - graphBounds.X; float yToMove = -graphBounds.Y; foreach (FCNode node in subgraph.Nodes) { RectangleF nodeBounds = node.Bounds; RectangleF oldBounds = node.Node.BoundingRect; nodeBounds.X += xToMove; nodeBounds.Y += yToMove; node.Bounds = nodeBounds; if (_layoutNode != null) _layoutNode(node.Node, oldBounds); } xOffset += graphBounds.Width; // Update arrows foreach (FCLink link in subgraph.Links) { Arrow arrow = link.Arrow; if (arrow.IgnoreLayout) continue; // If the arrow being arranged is dynamic, // ignore the anchoring flag? if (arrow.Dynamic) arrow.updatePosFromOrgAndDest(false); arrow.arrangePoints(_anchoring); if (_layoutLink != null) _layoutLink(arrow); } } chart.Invalidate(); chart.UndoManager.onEndLayout(); return true; }
public virtual bool Arrange(FlowChart chart) { chart.UndoManager.onStartLayout("Grid layout"); // Build the graph FCGraph graph = new FCGraph(chart, _keepGroupLayout); // Find the root adapter Layout.INode rootNode = null; if (_root != null) { foreach (FCNode node in graph.Nodes) { if (node.Node == _root) { rootNode = node; break; } } } // Split graph to subgraphs Layout.IGraph[] subgraphs = null; if (_splitGraph) { subgraphs = Layout.GraphSplitter.Split( graph, new FCGraphBuilder(chart, false)); } else { subgraphs = new Layout.IGraph[] { graph }; } // Create the layouter Layout.GridLayout layout = new Layout.GridLayout(); Layout.LayoutProgress progress = null; if (_progress != null) progress = new Layout.LayoutProgress(this.OnLayoutProgress); Layout.GridLayoutInfo info = new Layout.GridLayoutInfo(); info.GridSize = this.GridSize; info.Iterations = this.Iterations; info.XGap = this.XGap; info.YGap = this.YGap; info.RndSeed = this.RndSeed; float xOffset = XGap; foreach (FCGraph subgraph in subgraphs) { // If a root node is specified and the subgraph // does not contain that node, do not arrange // the subgraph if (rootNode != null) { if (!subgraph.Nodes.Contains(rootNode)) continue; } // Set the start and end nodes info.StartNode = null; info.EndNode = null; foreach (FCNode node in subgraph.Nodes) { if (node.Node == _startNode) info.StartNode = node; if (node.Node == _endNode) info.EndNode = node; } // Ensure both start and end nodes are set if (info.StartNode == null || info.EndNode == null) { info.StartNode = null; info.EndNode = null; } layout.Arrange(subgraph, info, progress); // Translate the whole subgraph RectangleF graphBounds = subgraph.GetBounds(false); float xToMove = xOffset - graphBounds.X; float yToMove = info.YGap - graphBounds.Y; foreach (FCNode node in subgraph.Nodes) { RectangleF nodeBounds = node.Bounds; RectangleF oldBounds = node.Node.BoundingRect; nodeBounds.X += xToMove; nodeBounds.Y += yToMove; node.Bounds = nodeBounds; if (_layoutNode != null) _layoutNode(node.Node, oldBounds); } xOffset += graphBounds.Width + info.GridSize; // Update arrows foreach (FCLink link in subgraph.Links) { if (link.Arrow.IgnoreLayout) continue; link.Arrow.arrangePoints(_anchoring); if (_layoutLink != null) _layoutLink(link.Arrow); } } chart.RouteAllArrows(); chart.Invalidate(); chart.UndoManager.onEndLayout(); return true; }
public virtual bool Arrange(FlowChart chart) { chart.UndoManager.onStartLayout("Layered layout"); // Disable undo to prevent unneeded actions. // For example: RouteAllArrows is invoked each time // when a new dummy box is created, which is a very // expensive operation even with no AutoRoute arrows present. bool undo = chart.UndoManager.UndoEnabled; chart.UndoManager.enable(false); // Build the graph FCGraph graph = new FCGraph(chart, _keepGroupLayout); // Find the root adapter Layout.INode rootNode = null; if (_root != null) { foreach (FCNode node in graph.Nodes) { if (node.Node == _root) { rootNode = node; break; } } } // Split graph to subgraphs Layout.IGraph[] subgraphs = Layout.GraphSplitter.Split( graph, new FCGraphBuilder(chart, false)); // Make sure all arrows are polylines with 1 segment. // Arrows' AutoRoute flag is also undesired. // Note: Process only the arrows belonging to // the subgraph, which contains the specified root (if any) if (rootNode == null) { foreach (Arrow arrow in chart.Arrows) { if (arrow.isReflexive()) continue; arrow.AutoRoute = false; arrow.Style = MindFusion.FlowChartX.ArrowStyle.Polyline; arrow.SegmentCount = 1; } } else { foreach (FCGraph subgraph in subgraphs) { if (subgraph.Nodes.Contains(rootNode)) { foreach (FCLink link in subgraph.Links) { Arrow arrow = link.Arrow; if (arrow.isReflexive()) continue; arrow.AutoRoute = false; arrow.Style = MindFusion.FlowChartX.ArrowStyle.Polyline; arrow.SegmentCount = 1; } break; } } } // Create the layouter Layout.LayeredLayout layout = new Layout.LayeredLayout(); Layout.LayoutProgress progress = null; if (_progress != null) progress = new Layout.LayoutProgress(this.OnLayoutProgress); Layout.LayeredLayoutInfo info = new Layout.LayeredLayoutInfo(); info.ArrowsCompactFactor = this.ArrowsCompactFactor; info.Direction = (Layout.Direction)this.Direction; info.LayerDistance = this.LayerDistance; info.NodeDistance = this.NodeDistance; info.Orientation = (Layout.Orientation)this.Orientation; info.SplitLayers = this.SplitLayers; info.XGap = this.XGap; info.YGap = this.YGap; info.TimeLimit = this.TimeLimit; float xOffset = this.XGap; foreach (FCGraph subgraph in subgraphs) { // If a root node is specified and the subgraph // does not contain that node, do not arrange // the subgraph if (rootNode != null) { if (!subgraph.Nodes.Contains(rootNode)) continue; } layout.Arrange(subgraph, info, progress); // Translate the whole subgraph RectangleF graphBounds = subgraph.GetBounds(true); float xToMove = xOffset - graphBounds.X; float yToMove = this.YGap - graphBounds.Y; foreach (FCNode node in subgraph.Nodes) { RectangleF nodeBounds = node.Bounds; RectangleF oldBounds = node.Node.BoundingRect; nodeBounds.X += xToMove; nodeBounds.Y += yToMove; node.Bounds = nodeBounds; if (_layoutNode != null) _layoutNode(node.Node, oldBounds); } // Update arrows' inner points; the end points // must have already been offset by the loop above foreach (FCLink link in subgraph.Links) { // Arrows that retain form need not be updated if (link.Arrow.RetainForm) continue; for (int i = 1; i < link.Arrow.Points.Count - 1; i++) { PointF pt = link.Arrow.Points[i]; pt.X += xToMove; pt.Y += yToMove; link.Arrow.Points[i] = pt; } } xOffset += graphBounds.Width + this.XGap; // Update arrows foreach (FCLink link in subgraph.Links) { Arrow arrow = link.Arrow; if (arrow.IgnoreLayout) continue; // Update end points if (arrow.SegmentCount == 1) { arrow.arrangePoints(_anchoring); } else { int orgnAnchor = arrow.OrgnAnchor; int destAnchor = arrow.DestAnchor; arrow.Points[0] = arrow.getOrgnLink().getIntersection( arrow.Origin.getCenter(), arrow.Points[1]); arrow.Points[arrow.Points.Count - 1] = arrow.getDestLink().getIntersection( arrow.Points[arrow.Points.Count - 2], arrow.Destination.getCenter()); switch (_anchoring) { case Anchoring.Ignore: // Do nothing break; case Anchoring.Keep: if (orgnAnchor >= 0) { arrow.OrgnAnchor = -1; arrow.OrgnAnchor = orgnAnchor; } if (destAnchor >= 0) { arrow.DestAnchor = -1; arrow.DestAnchor = destAnchor; } break; case Anchoring.Reassign: arrow.Points[0] = arrow.Origin.getNearestAnchor( arrow.Points[0], arrow, false, ref orgnAnchor); arrow.Points[arrow.Points.Count - 1] = arrow.Destination.getNearestAnchor( arrow.Points[arrow.Points.Count - 1], arrow, true, ref destAnchor); arrow.setOrgnAnchor(orgnAnchor); arrow.setDestAnchor(destAnchor); break; } } arrow.UpdateFromPoints(); if (_layoutLink != null) _layoutLink(arrow); } } chart.Invalidate(); chart.UndoManager.enable(undo); chart.UndoManager.onEndLayout(); return true; }
public virtual bool Arrange(FlowChart chart) { chart.UndoManager.onStartLayout("Spring layout"); // Build the graph FCGraph graph = new FCGraph(chart, _keepGroupLayout); // Find the root adapter Layout.INode rootNode = null; if (_root != null) { foreach (FCNode node in graph.Nodes) { if (node.Node == _root) { rootNode = node; break; } } } // Split graph to subgraphs Layout.IGraph[] subgraphs = Layout.GraphSplitter.Split( graph, new FCGraphBuilder(chart, false)); // Create the layouter Layout.SpringLayout layout = new Layout.SpringLayout(); layout.Stretch = _stretch; Layout.LayoutProgress progress = null; if (_progress != null) progress = new Layout.LayoutProgress(this.OnLayoutProgress); Layout.SpringLayoutInfo info = new Layout.SpringLayoutInfo(); info.IterationCount = this.IterationCount; info.MinimizeCrossings = this.MinimizeCrossings; info.NodeDistance = this.NodeDistance; info.EnableClusters = this.EnableClusters; info.RepulsionFactor = this.RepulsionFactor; info.RndSeed = this.RndSeed; float xOffset = 0; foreach (FCGraph subgraph in subgraphs) { // If a root node is specified and the subgraph // does not contain that node, do not arrange // the subgraph if (rootNode != null) { if (!subgraph.Nodes.Contains(rootNode)) continue; } layout.Arrange(subgraph, info, progress); // Translate the whole subgraph RectangleF graphBounds = subgraph.GetBounds(false); float xToMove = xOffset - graphBounds.X; float yToMove = -graphBounds.Y; foreach (FCNode node in subgraph.Nodes) { RectangleF nodeBounds = node.Bounds; RectangleF oldBounds = node.Node.BoundingRect; nodeBounds.X += xToMove; nodeBounds.Y += yToMove; node.Bounds = nodeBounds; if (_layoutNode != null) _layoutNode(node.Node, oldBounds); } xOffset += graphBounds.Width + this.NodeDistance; // Update arrows foreach (FCLink link in subgraph.Links) { Arrow arrow = link.Arrow; if (arrow.IgnoreLayout) continue; // If the arrow being arranged is dynamic, // ignore the anchoring flag? if (arrow.Dynamic) arrow.updatePosFromOrgAndDest(false); arrow.arrangePoints(_anchoring); if (_layoutLink != null) _layoutLink(arrow); } } chart.Invalidate(); chart.UndoManager.onEndLayout(); return true; }
/// <summary> /// Performs the arrangement. /// </summary> public virtual bool Arrange(FlowChart chart) { if (_ignoreArrowDirection && _root == null) return false; chart.UndoManager.onStartLayout("Tree layout"); // Build the graph FCGraph graph = null; if (_reversedArrows) { graph = new ReversedFCGraph(chart, _keepGroupLayout, _ignoreArrowDirection); } else { graph = new FCGraph(chart, _keepGroupLayout, _ignoreArrowDirection); } // Get the root node within the graph Layout.INode rootNode = null; if (_root != null) { foreach (FCNode node in graph.Nodes) { if (node.Node == _root) { rootNode = node; break; } } } CalculateAnchors(); // Split graph to subgraphs Layout.IGraph[] subgraphs = Layout.GraphSplitter.Split(graph, new FCGraphBuilder(chart, _reversedArrows)); float xOffset = this.XGap; foreach (FCGraph subgraph in subgraphs) { Layout.INode theRoot = null; if (subgraph.Nodes.Contains(rootNode)) { // The root node of the user is within this // subgraph - respect the user's wishes theRoot = rootNode; } else { // If the user specified a root node, // arrange only the graph, containing // that node if (rootNode != null) continue; // If the subgraph has root node, use it, // otherwise select the first node as root Layout.INode subRoot = subgraph.Root; if (subRoot == null) theRoot = subgraph.Nodes[0]; else theRoot = subRoot; } // Check if the root is layoutable if ((theRoot as FCNode).Node.Frozen) continue; Layout.LayoutProgress progress = null; if (_progress != null) progress = new Layout.LayoutProgress( this.OnLayoutProgress); Layout.TreeLayoutInfo info = new Layout.TreeLayoutInfo(); info.Direction = (Layout.TreeLayoutDirection)this.Direction; info.KeepRootPosition = this.KeepRootPosition; info.LevelDistance = this.LevelDistance; info.NodeDistance = this.NodeDistance; info.StretchFactor = this.StretchFactor; info.XGap = this.XGap; info.YGap = this.YGap; if (_layoutNode != null) { // remember the old positions foreach (FCNode node in subgraph.Nodes) node.Node.setData(Constants.OLD_BOUNDS, node.Node.BoundingRect); } // Arrange the subgraph switch (_type) { case TreeLayoutType.Cascading: new Layout.BorderTreeLayout().Arrange( theRoot, info, progress); break; case TreeLayoutType.Centered: new Layout.CenterTreeLayout().Arrange( theRoot, info, progress); break; case TreeLayoutType.Radial: new Layout.RadialTreeLayout().Arrange( theRoot, info, progress); break; } // If the root is not at fixed position, translate the whole tree if (!this.KeepRootPosition) { RectangleF graphBounds = subgraph.GetBounds(false); float xToMove = xOffset - graphBounds.X; float yToMove = this.YGap - graphBounds.Y; foreach (FCNode node in subgraph.Nodes) { RectangleF nodeBounds = node.Bounds; nodeBounds.X += xToMove; nodeBounds.Y += yToMove; node.Bounds = nodeBounds; } xOffset += graphBounds.Width + this.XGap; } if (_layoutNode != null) { // raise the LayoutNode event for each node foreach (FCNode node in subgraph.Nodes) _layoutNode(node.Node, (RectangleF)node.Node.getData(Constants.OLD_BOUNDS)); chart.clearRuntimeData(Constants.OLD_BOUNDS); } // Update the arrows in this particular subgraph ArrayList visitedLinks = new ArrayList(); ArrayList nodes = new ArrayList(); nodes.Add(theRoot); while (nodes.Count > 0) { FCNode node = nodes[0] as FCNode; nodes.RemoveAt(0); if (node.Node.Frozen) continue; foreach (FCLink link in node.OutLinks) { if (!visitedLinks.Contains(link)) { visitedLinks.Add(link); if (!link.Arrow.IgnoreLayout) { if (link.Destination == node) { UpdateArrow(link.Arrow, true); nodes.Add(link.Origin); } else { UpdateArrow(link.Arrow, false); nodes.Add(link.Destination); } if (_layoutLink != null) _layoutLink(link.Arrow); } } } } } chart.Invalidate(); chart.UndoManager.onEndLayout(); return true; }