using System.Collections.Generic; using Microsoft.Msagl.Core.GraphAlgorithms; using Microsoft.Msagl.Core.Layout; namespace Microsoft.Msagl.Layout.Layered { /// /// Preparing the graph for x-coordinate calculation by inserting dummy nodes into the layers /// internal class LayerInserter { BasicGraph intGraph; Database database; /// /// Old layered graph: /// ProperLayeredGraph layeredGraph; /// /// new layered graph /// ProperLayeredGraph nLayeredGraph; IntEdge[] virtNodesToIntEdges; internal ProperLayeredGraph NLayeredGraph { get { return nLayeredGraph; } } /// /// old layer arrays /// LayerArrays la; /// /// new layer arrays /// LayerArrays nla; internal LayerArrays Nla { get { return nla; } } /// /// constructor /// /// /// /// /// LayerInserter( ProperLayeredGraph layeredGraph, LayerArrays la, Database database, BasicGraph intGraphP) { this.la = la; this.database = database; this.layeredGraph = layeredGraph; this.intGraph = intGraphP; } ///// ///// the entry point of the class ///// ///// ///// ///// static internal void InsertLayers( ref ProperLayeredGraph layeredGraph, ref LayerArrays la, Database db, BasicGraph intGraphP) { LayerInserter li = new LayerInserter(layeredGraph, la, db, intGraphP); li.InsertLayers(); layeredGraph = li.NLayeredGraph; la = li.Nla.DropEmptyLayers(); } /// /// new Y-layering /// int[] NLayering { get { return this.nla.Y; } } /// /// does the main work /// void InsertLayers() { EditOldLayering(); CreateFullLayeredGraph(); InitNewLayering(); MapVirtualNodesToEdges(); FillUnsortedNewOddLayers(); WidenOriginalLayers(); SortNewOddLayers(); } /// /// virtual nodes inside of an edge should be of the form i,i+1, .... /// private void EditOldLayering() { int curVNode = this.intGraph.NodeCount; foreach (List list in database.RegularMultiedges) { int span = 0; IntEdge e = list[0]; span = e.LayerSpan * 2; if (span > 0) {//ignoring flat edges foreach (LayerEdge le in e.LayerEdges) { if (le.Target != e.Target) { curVNode++; UpdateOldLayer(curVNode++, le.Target); } } curVNode += (span - 1) * (list.Count - 1) + 1; } } } private void UpdateOldLayer(int replacingNode, int prevNode) { int x = this.la.X[prevNode]; int y = this.la.Y[prevNode]; int[] layer = this.la.Layers[y]; layer[x] = replacingNode; // this.la.X[replacingNode] = x; // this.la.Y[replacingNode] = y; } /// /// Original layers are represented by even layers in the new layering. /// Here we add new virtices in such layers and /// set new x-offsets of original and dummy vertices in these layers. /// void WidenOriginalLayers() { for (int i = 0; i < la.Layers.Length; i++) { int[] layer = nla.Layers[i * 2]; int offset = 0; foreach (int v in la.Layers[i]) { IntEdge e = virtNodesToIntEdges[v]; if (e != null) { int layerOffsetInTheEdge = NLayering[e.Source] - NLayering[v]; List list = database.Multiedges[new IntPair(e.Source, e.Target)]; foreach (IntEdge ie in list) { if (ie != e) { int u = ie.LayerEdges[layerOffsetInTheEdge].Source; layer[offset] = u; nla.X[u] = offset++; } else { layer[offset] = v; nla.X[v] = offset++; } } } else { layer[offset] = v; nla.X[v] = offset++; } } } } /// /// filling new layers not corresponding to the original layers /// void FillUnsortedNewOddLayers() { int[] c = new int[nla.Layers.Length]; for (int i = intGraph.NodeCount; i < nLayeredGraph.NodeCount; i++) { int layer = NLayering[i]; if (layer % 2 == 1) {//new layers have odd numbers nla.Layers[layer][c[layer]++] = i; } } } /// /// create the mapping from the vertices to edges to which they belong /// void MapVirtualNodesToEdges() { virtNodesToIntEdges = new IntEdge[this.NLayering.Length]; foreach (IntEdge e in database.AllIntEdges) if (e.Source != e.Target && e.LayerEdges!=null) foreach (LayerEdge le in e.LayerEdges) if (le.Target != e.Target) virtNodesToIntEdges[le.Target] = e; } int totalNodes; /// /// Creating buckets for multi edges and allocating the graph. /// private void CreateFullLayeredGraph() { totalNodes = this.intGraph.NodeCount; foreach (List list in database.RegularMultiedges) { int span = 0; bool first = true; foreach (IntEdge e in list) { if (first) { first = false; span = e.LayerSpan * 2; } if (span > 0) { e.LayerEdges = new LayerEdge[span]; for (int i = 0; i < span; i++) { int source = EdgePathsInserter.GetSource(ref totalNodes, e, i); int target = EdgePathsInserter.GetTarget(ref totalNodes, e, i, span); e.LayerEdges[i] = new LayerEdge(source, target, e.CrossingWeight); } LayerInserter.RegisterDontStepOnVertex(this.database, e); } } } this.nLayeredGraph = new ProperLayeredGraph(this.intGraph); } /// /// Sort new odd layers by the sum of x-coordinatates of predecessors and the successors of /// dummy nodes. /// void SortNewOddLayers() { for (int i = 1; i < nla.Layers.Length; i += 2) { SortedDictionary sd = new SortedDictionary(); int[] layer = nla.Layers[i]; foreach (int v in layer) { //find unique predecessor and successor int predecessor = -1; foreach (LayerEdge ie in nLayeredGraph.InEdges(v)) predecessor = ie.Source; int successor = -1; foreach (LayerEdge ie in nLayeredGraph.OutEdges(v)) successor = ie.Target; int x = nla.X[predecessor] + nla.X[successor]; if (sd.ContainsKey(x)) { object o = sd[x]; #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=347 if (o.GetType() == typeof(int)) { #else if (o is int) { #endif List l = new List(); l.Add((int)o); l.Add(v); sd[x] = l; } else { List l = o as List; l.Add(v); } } else sd[x] = v; } //fill the layer according to this order int c = 0; foreach (object v in sd.Values) #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=347 if (v.GetType() == typeof(int)) #else if (v is int) #endif layer[c++] = (int)v; else foreach (int k in v as List) layer[c++] = k; //update X now for (int m = 0; m < layer.Length; m++) nla.X[layer[m]] = m; } } /// /// Allocating new layering and filling its y-layers /// void InitNewLayering() { nla = new LayerArrays(new int[totalNodes]); for (int i = 0; i < layeredGraph.NodeCount; i++) NLayering[i] = la.Y[i] * 2; foreach (KeyValuePair> kv in database.Multiedges) { IntPair ip = kv.Key; if (ip.First != ip.Second && la.Y[ip.First] != la.Y[ip.Second]) {//not a self edge and not a flat edge int top = la.Y[ip.x] * 2; foreach (IntEdge e in kv.Value) { int layer = top - 1; foreach (LayerEdge le in e.LayerEdges) if (le.Target != e.Target) NLayering[le.Target] = layer--; } } } int[][] newLayers = new int[2 * la.Layers.Length - 1][]; //count new layer widths int[] counts = new int[newLayers.Length]; foreach (int l in NLayering) counts[l]++; for (int i = 0; i < counts.Length; i++) newLayers[i] = new int[counts[i]]; nla = new LayerArrays(NLayering); nla.Layers = newLayers; } ///// ///// mark the vertex as one representing a label ///// or a middle of a multi edge ///// ///// ///// ///// ///// internal static void RegisterDontStepOnVertex(Database db, IntEdge parent) { if (db.Multiedges[new IntPair(parent.Source, parent.Target)].Count > 1) { LayerEdge e = parent.LayerEdges[parent.LayerEdges.Count / 2]; db.MultipleMiddles.Insert(e.Source); } } } }