private void Traverse(profile p, int currentCheckedLevel, bool depthFirst, Action <bool, profile, profile> callback) { List <profile> uncheckedProfiles = null; if (depthFirst) { uncheckedProfiles = new List <profile>(); } for (int i = 0; i < p.forward.Count; i++) { profile f = p.forward[i]; if (f.Checked(currentCheckedLevel)) { continue; } callback.Invoke(true, p, f); if (depthFirst) { uncheckedProfiles.Add(f); } else { Traverse(f, currentCheckedLevel, false, callback); } } for (int i = 0; i < p.backward.Count; i++) { profile b = p.backward[i]; if (b.Checked(currentCheckedLevel)) { continue; } callback.Invoke(false, p, b); if (depthFirst) { uncheckedProfiles.Add(b); } else { Traverse(b, currentCheckedLevel, false, callback); } } if (depthFirst) { for (int i = 0; i < uncheckedProfiles.Count; i++) { Traverse(uncheckedProfiles[i], currentCheckedLevel, true, callback); } } }
public void Layout() { if (Graph == null) { return; } profiles = new List <profile>(); profilesByNode = new Dictionary <NoFlo_Basic.Component, profile>(); foreach (NoFlo_Basic.Component c in Graph.NodesByName.Values) { profile p = new profile() { Component = c, }; profilesByNode.Add(c, p); profiles.Add(p); } for (int i = 0; i < profiles.Count; i++) { profile p = profiles[i]; p.forward = ForwardConnectedNodes(p.Component); p.backward = BackwardConnectedNodes(p.Component); } // 0 or 1, already done if (profiles.Count <= 1) { return; } int currentCheckedLevel = 1; // Check each profile only if they haven't been checked yet for (int i = 0; i < profiles.Count; i++) { profile p = profiles[i]; if (p.Checked(currentCheckedLevel)) { continue; } // Set initial rank p.rank = 0; // Traverse the network, checking each profile. // Each forward connections adds one to the rank, each backward substracts one Traverse(p, currentCheckedLevel, true, (isForward, l, h) => { h.rank = l.rank.Value + (isForward ? 1 : -1); }); } currentCheckedLevel = 2; float hsep = GraphEditor.Layout.HorizontalSeparation; float vsep = GraphEditor.Layout.VerticalSeparation; List <int> OrderedRanks; Dictionary <int, List <profile> > profilesByRank = OrderProfilesByRank(out OrderedRanks); Dictionary <int, int> NumberOfNodesGraphedByRank = new Dictionary <int, int>(); Func <profile, int, float> xPos = (p, o) => (p.rank.Value + o) * hsep; Func <float, int, float> yPos = (y, n) => y + n * vsep; foreach (int r in profilesByRank.Keys) { NumberOfNodesGraphedByRank.Add(r, 0); } // Position according to rank, for each sub graph for (int i = 0; i < OrderedRanks.Count; i++) { int rank = OrderedRanks[i]; List <profile> profileOfRank = profilesByRank[rank]; int rankOffset; if (rank < 0) { rankOffset = -rank; } else { rankOffset = 0; } for (int j = 0; j < profileOfRank.Count; j++) { float currentY = rank * vsep; // TODO include full size of previous graph profile p = profileOfRank[j]; if (p.Checked(currentCheckedLevel)) { continue; } p.Component.MetadataPosition = new Vector3(xPos(p, rankOffset), yPos(currentY, 0)); Traverse(p, currentCheckedLevel, true, (isForward, l, h) => { int number = NumberOfNodesGraphedByRank[h.rank.Value]; NumberOfNodesGraphedByRank[h.rank.Value] = number + 1; h.Component.MetadataPosition = new Vector3(xPos(h, rankOffset), yPos(currentY, number)); }); } } // Center the whole graph at the local zero for the panel GraphEditor.CenterGraph(); }