/// <summary> /// constructor /// </summary> /// <param name="layeredGraph"></param> /// <param name="la"></param> /// <param name="database"></param> /// <param name="intGraphP"></param> LayerInserter( ProperLayeredGraph layeredGraph, LayerArrays la, Database database, BasicGraph<Node, IntEdge> intGraphP) { this.la = la; this.database = database; this.layeredGraph = layeredGraph; this.intGraph = intGraphP; }
/// <summary> /// Returns the same arrays but with no empty layers. /// </summary> /// <returns></returns> internal LayerArrays DropEmptyLayers() { int[] drop = new int[this.Layers.Length]; int dropVal = 0; for (int i = 0; i < this.Layers.Length; i++) { drop[i] = dropVal; if (this.Layers[i].Length == 0) dropVal++; } if (dropVal == 0) return this; //we do have empty layers int[] ny = new int[Y.Length]; for (int i = 0; i < ny.Length; i++) ny[i] = Y[i] - drop[Y[i]]; //copy the layers itself int[][] nls = new int[this.layers.Length - dropVal][]; for (int i = 0; i < layers.Length; i++) { if (layers[i].Length > 0) nls[i - drop[i]] = (int[])layers[i].Clone(); } LayerArrays la = new LayerArrays(ny); la.layers = nls; return la; }
static Dictionary <int, Point> BuildInitialNodePositions(ProperLayeredGraph properLayeredGraph, LayerArrays layerArrays) { var result = new Dictionary <int, Point>(); for (int i = 0; i < layerArrays.Layers.Length; i++) { int prev = 0, curr = 0; while (curr < layerArrays.Layers[i].Length) { while (curr < layerArrays.Layers[i].Length && properLayeredGraph.IsVirtualNode(layerArrays.Layers[i][curr])) { curr++; } for (int j = prev; j < curr; j++) { result[layerArrays.Layers[i][j]] = new Point(i, prev); } if (curr < layerArrays.Layers[i].Length) { result[layerArrays.Layers[i][curr]] = new Point(i, curr); } curr++; prev = curr; } } return(result); }
MetroMapOrdering(ProperLayeredGraph properLayeredGraph, LayerArrays layerArrays, Dictionary <int, Point> nodePositions) { this.properLayeredGraph = properLayeredGraph; this.layerArrays = layerArrays; this.nodePositions = nodePositions; }
static internal void InsertPaths( ref ProperLayeredGraph layeredGraph, ref LayerArrays la, Database db, BasicGraph<Node, IntEdge> intGraphP) { EdgePathsInserter li = new EdgePathsInserter(layeredGraph, la, db, intGraphP); li.InsertPaths(); layeredGraph = li.NLayeredGraph; la = li.Nla; }
///// <summary> ///// the entry point of the class ///// </summary> ///// <param name="layeredGraph"></param> ///// <param name="la"></param> ///// <param name="db"></param> static internal void InsertLayers( ref ProperLayeredGraph layeredGraph, ref LayerArrays la, Database db, BasicGraph<Node, IntEdge> intGraphP) { LayerInserter li = new LayerInserter(layeredGraph, la, db, intGraphP); li.InsertLayers(); layeredGraph = li.NLayeredGraph; la = li.Nla.DropEmptyLayers(); }
static internal void InsertPaths( ref ProperLayeredGraph layeredGraph, ref LayerArrays la, Database db, BasicGraph <Node, IntEdge> intGraphP) { EdgePathsInserter li = new EdgePathsInserter(layeredGraph, la, db, intGraphP); li.InsertPaths(); layeredGraph = li.NLayeredGraph; la = li.Nla; }
internal AdjacentSwapsWithConstraints(LayerArrays layerArray, bool hasCrossWeights, ProperLayeredGraph properLayeredGraph, LayerInfo[] layerInfos) { X = layerArray.X; layering = layerArray.Y; layers = layerArray.Layers; this.properLayeredGraph = properLayeredGraph; this.hasCrossWeights = hasCrossWeights; this.layerInfos = layerInfos; }
internal static int GetCrossingsTotal(ProperLayeredGraph properLayeredGraph, LayerArrays layerArrays) { int x = 0; for (int i = 0; i < layerArrays.Layers.Length - 1; i++) { x += GetCrossingCountFromStrip(i, properLayeredGraph, layerArrays); } return(x); }
/// <summary> /// Creates a smoothed polyline /// </summary> internal SmoothedPolylineCalculator(IntEdge edgePathPar, Anchor[] anchorsP, GeometryGraph origGraph, SugiyamaLayoutSettings settings, LayerArrays la, ProperLayeredGraph layerGraph, Database databaseP) { this.database = databaseP; edgePath = edgePathPar; anchors = anchorsP; this.layerArrays = la; this.originalGraph = origGraph; this.settings = settings; this.layeredGraph = layerGraph; rightHierarchy = BuildRightHierarchy(); leftHierarchy = BuildLeftHierarchy(); }
int weightMultiplierOfTwoVirtual = 8; //weight multiplier for edges with two virtual nodes internal XLayoutGraph(BasicGraph <IntEdge> graph, //DAG of the original graph with no multiple edges ProperLayeredGraph layeredGraph, LayerArrays layerArrays, List <IntEdge> edges, int nov) { this.SetEdges(edges, nov); this.virtualVerticesStart = graph.NodeCount; this.virtualVerticesEnd = layeredGraph.NodeCount - 1; this.layeredGraph = layeredGraph; this.layerArrays = layerArrays; }
internal Routing(SugiyamaLayoutSettings settings, GeometryGraph originalGraph, Database dbP, LayerArrays yLayerArrays, ProperLayeredGraph properLayeredGraph, BasicGraph<Node, PolyIntEdge> intGraph ) { this.settings = settings; OriginalGraph = originalGraph; Database = dbP; ProperLayeredGraph = properLayeredGraph; LayerArrays = yLayerArrays; IntGraph = intGraph; }
internal Routing(SugiyamaLayoutSettings settings, GeometryGraph originalGraph, Database dbP, LayerArrays yLayerArrays, ProperLayeredGraph properLayeredGraph, BasicGraph<Node, IntEdge> intGraph ) { this.settings = settings; OriginalGraph = originalGraph; Database = dbP; ProperLayeredGraph = properLayeredGraph; LayerArrays = yLayerArrays; IntGraph = intGraph; }
void InitNewLayering() { nla = new LayerArrays(new int[this.NLayeredGraph.NodeCount]); for (int i = 0; i < layeredGraph.NodeCount; i++) { NLayering[i] = la.Y[i]; } foreach (KeyValuePair <IntPair, List <IntEdge> > kv in database.Multiedges) { if (kv.Key.First != kv.Key.Second && la.Y[kv.Key.First] != la.Y[kv.Key.Second]) //not a self edge and not a flat edge { int layer = 0; bool first = true; List <IntEdge> list = kv.Value; foreach (IntEdge e in list) { if (first) { first = false; layer = la.Y[e.Source]; } int cl = layer - 1; foreach (LayerEdge le in e.LayerEdges) { NLayering[le.Target] = cl--; } } } } int[][] newLayers = new int[la.Layers.Length][]; //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; }
Ordering(ProperLayeredGraph graphPar, bool tryReverse, LayerArrays layerArraysParam, int startOfVirtualNodes, bool balanceVirtualAndOrigNodes, bool hasCrossWeights, SugiyamaLayoutSettings settings) { this.tryReverse = tryReverse; startOfVirtNodes = startOfVirtualNodes; layerArrays = layerArraysParam; layering = layerArraysParam.Y; nOfLayers = layerArraysParam.Layers.Length; layers = layerArraysParam.Layers; balanceVirtAndOrigNodes = balanceVirtualAndOrigNodes; properLayeredGraph = graphPar; this.hasCrossWeights = hasCrossWeights; this.settings = settings; random = new Random(SeedOfRandom); }
Ordering(ProperLayeredGraph graphPar, bool tryReverse, LayerArrays layerArraysParam, int startOfVirtualNodes, bool hasCrossWeights, SugiyamaLayoutSettings settings) { this.tryReverse = tryReverse; startOfVirtNodes = startOfVirtualNodes; layerArrays = layerArraysParam; layering = layerArraysParam.Y; nOfLayers = layerArraysParam.Layers.Length; layers = layerArraysParam.Layers; properLayeredGraph = graphPar; this.hasCrossWeights = hasCrossWeights; this.settings = settings; random = new Random(SeedOfRandom); }
///// <summary> ///// private constructor ///// </summary> ///// <param name="layerArrays"></param> ///// <param name="anchs"></param> ///// <param name="layeredGraph"></param> ///// <param name="nOfOriginalVs"></param> XCoordsWithAlignment(LayerArrays layerArrays, ProperLayeredGraph layeredGraph, int nOfOriginalVs, Anchor[] anchorsP, double ns) { this.la = layerArrays; this.graph = layeredGraph; this.nOfOriginalVertices = nOfOriginalVs; this.nOfVertices = graph.NodeCount; this.h = la.Layers.Length; this.root = new int[nOfVertices]; this.align = new int[nOfVertices]; // this.sink = new int[nOfVertices]; // this.shift = new double[nOfVertices]; this.anchors = anchorsP; this.nodeSep = ns; }
internal static void OrderLayers(ProperLayeredGraph graph, LayerArrays layerArrays, int startOfVirtualNodes, bool balanceVirtualAndOriginalNodes, SugiyamaLayoutSettings settings, CancelToken cancelToken) { bool hasCrossWeight = false; foreach (LayerEdge le in graph.Edges) if (le.CrossingWeight != 1) { hasCrossWeight = true; break; } var o = new Ordering(graph, true, layerArrays, startOfVirtualNodes, balanceVirtualAndOriginalNodes, hasCrossWeight, settings); o.Run(cancelToken); }
internal static void Refine( int topNodeP, int bottomNode, Site topSiteP, Anchor[] anchors, LayerArrays layerArraysP, ProperLayeredGraph layeredGraph, GeometryGraph originalGraph, double layerSeparation) { RefinerBetweenTwoLayers refiner = new RefinerBetweenTwoLayers(topNodeP, bottomNode, topSiteP, layerArraysP, layeredGraph, originalGraph, anchors, layerSeparation); refiner.Refine(); }
/// <summary> /// it is a special recovery constructor to recreate the engine from the recovery engine /// </summary> internal LayeredLayoutEngine(LayerArrays engineLayerArrays, GeometryGraph originalGraph, ProperLayeredGraph properLayeredGraph, SugiyamaLayoutSettings sugiyamaSettings, Database database, BasicGraph<Node, IntEdge> intGraph, Dictionary<Node, int> nodeIdToIndex, BasicGraph<Node, IntEdge> gluedDagSkeletonForLayering, bool layersAreDoubled, ConstrainedOrdering constrainedOrdering, bool brandes, XLayoutGraph xLayoutGraph) { this.engineLayerArrays = engineLayerArrays; this.originalGraph = originalGraph; this.properLayeredGraph = properLayeredGraph; this.sugiyamaSettings = sugiyamaSettings; this.database = database; IntGraph = intGraph; this.nodeIdToIndex = nodeIdToIndex; GluedDagSkeletonForLayering = gluedDagSkeletonForLayering; LayersAreDoubled = layersAreDoubled; this.constrainedOrdering = constrainedOrdering; Brandes = brandes; anchors = database.anchors; this.xLayoutGraph = xLayoutGraph; }
/// <summary> /// Allocating new layering and filling its y-layers /// </summary> void InitNewLayering() { nla = new LayerArrays(new int[totalNodes]); for (int i = 0; i < layeredGraph.NodeCount; i++) { NLayering[i] = la.Y[i] * 2; } foreach (KeyValuePair <IntPair, List <IntEdge> > 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; }
RefinerBetweenTwoLayers( int topNodeP, int bottomNodeP, Site topSiteP, LayerArrays layerArraysP, ProperLayeredGraph layeredGraphP, GeometryGraph originalGraphP, Anchor[] anchorsP, double layerSeparation) { this.topNode = topNodeP; this.bottomNode = bottomNodeP; this.topSite = topSiteP; this.bottomSite = topSiteP.Next; this.currentTopSite = topSiteP; this.currentBottomSite = topSiteP.Next; this.layerArrays = layerArraysP; this.layeredGraph = layeredGraphP; this.originalGraph = originalGraphP; this.anchors = anchorsP; this.layerSeparation = layerSeparation; }
/// <summary> /// Returns the same arrays but with no empty layers. /// </summary> /// <returns></returns> internal LayerArrays DropEmptyLayers() { int[] drop = new int[this.Layers.Length]; int dropVal = 0; for (int i = 0; i < this.Layers.Length; i++) { drop[i] = dropVal; if (this.Layers[i].Length == 0) { dropVal++; } } if (dropVal == 0) { return(this); } //we do have empty layers int[] ny = new int[Y.Length]; for (int i = 0; i < ny.Length; i++) { ny[i] = Y[i] - drop[Y[i]]; } //copy the layers itself int[][] nls = new int[this.layers.Length - dropVal][]; for (int i = 0; i < layers.Length; i++) { if (layers[i].Length > 0) { nls[i - drop[i]] = (int[])layers[i].Clone(); } } LayerArrays la = new LayerArrays(ny); la.layers = nls; return(la); }
void CreateExtendedLayerArrays() { var layeringExt = new int[numberOfNodesOfProperGraph]; Array.Copy(initialLayering, layeringExt, initialLayering.Length); foreach (IntEdge edge in ProperLayeredGraph.BaseGraph.Edges) { var ledges = (LayerEdge[])edge.LayerEdges; if (ledges != null && ledges.Length > 1) { int layerIndex = initialLayering[edge.Source] - 1; for (int i = 0; i < ledges.Length - 1; i++) { layeringExt[ledges[i].Target] = layerIndex--; } } } LayerArrays = new LayerArrays(layeringExt); }
static Dictionary<int, Point> BuildInitialNodePositions(ProperLayeredGraph properLayeredGraph, LayerArrays layerArrays) { var result = new Dictionary<int, Point>(); for (int i = 0; i < layerArrays.Layers.Length; i++) { int prev = 0, curr = 0; while (curr < layerArrays.Layers[i].Length) { while (curr < layerArrays.Layers[i].Length && properLayeredGraph.IsVirtualNode(layerArrays.Layers[i][curr])) curr++; for (int j = prev; j < curr; j++) result[layerArrays.Layers[i][j]] = new Point(i, prev); if (curr < layerArrays.Layers[i].Length) result[layerArrays.Layers[i][curr]] = new Point(i, curr); curr++; prev = curr; } } return result; }
internal static void OrderLayers(ProperLayeredGraph graph, LayerArrays layerArrays, int startOfVirtualNodes, SugiyamaLayoutSettings settings, CancelToken cancelToken) { bool hasCrossWeight = false; foreach (LayerEdge le in graph.Edges) { if (le.CrossingWeight != 1) { hasCrossWeight = true; break; } } var o = new Ordering(graph, true, layerArrays, startOfVirtualNodes, hasCrossWeight, settings); o.Run(cancelToken); }
static int GetCrossingCountFromStripWhenBottomLayerIsShorter(int[] bottomVerts, ProperLayeredGraph properLayeredGraph, LayerArrays layerArrays) { LayerEdge[] edges = EdgesOfStrip(bottomVerts, properLayeredGraph); Array.Sort(edges, new EdgeComparerBySource(layerArrays.X)); //find first n such that 2^n >=bottomVerts.Length int n = 1; while (n < bottomVerts.Length) { n *= 2; } //init accumulator var tree = new int[2 * n - 1]; n--; // the first bottom node starts from n now int cc = 0; //number of crossings foreach (LayerEdge edge in edges) { int index = n + layerArrays.X[edge.Target]; int ew = edge.CrossingWeight; tree[index] += ew; while (index > 0) { if (index % 2 != 0) { cc += ew * tree[index + 1]; //intersect everything accumulated in the right sibling } index = (index - 1) / 2; tree[index] += ew; } } return(cc); }
override protected void RunInternal() { #if REPORTING Timer t = null; if (sugiyamaSettings.Reporting) { Report("removing cycles ... "); t = new Timer(); t.Start(); } #endif if (originalGraph.Nodes.Count > 0) { engineLayerArrays = CalculateLayers(); if (!sugiyamaSettings.LayeringOnly) RunPostLayering(); } else originalGraph.boundingBox.SetToEmpty(); #if REPORTING if (sugiyamaSettings.Reporting) { t.Stop(); Report(String.Format(CultureInfo.InvariantCulture, "done for {0}, nodes {1} edges {2}", t.Duration, IntGraph.NodeCount, IntGraph.Edges.Count)); } //SugiyamaLayoutSettings.ShowDatabase(database); #endif }
static double SetFlatEdgesForLayer(Database database, LayerArrays layerArrays, int i, BasicGraph<IntEdge> intGraph, SugiyamaLayoutSettings settings, double ymax) { double flatEdgesHeight = 0; if (i > 0) { //looking for flat edges on the previous level //we stack labels of multiple flat edges on top of each other IEnumerable<IntPair> flatPairs = GetFlatPairs(layerArrays.Layers[i - 1], layerArrays.Y, intGraph); if (flatPairs.Any()) { double dyOfFlatEdge = settings.LayerSeparation/3; double ym = ymax; flatEdgesHeight = (from pair in flatPairs select SetFlatEdgesLabelsHeightAndPositionts(pair, ym, dyOfFlatEdge, database)). Max(); } } return flatEdgesHeight; }
///// <summary> ///// A quote from Gansner93. ///// The method involves constructing an auxiliary graph as illustrated in figure 4-2. ///// This transformation is the graphical analogue of the algebraic ///// transformation mentioned above for removing the absolute values ///// from the optimization problem. The nodes of the auxiliary graph Gў are the nodes of ///// the original graph G plus, for every edge e in G, there is a new node ne. ///// There are two kinds of edges in Gў. One edge class encodes the ///// cost of the original edges. Every edge e = (u,v) in G is replaced by two edges (ne ,u) ///// and (ne, v) with d = 0 and w = w(e)W(e). The other class of edges separates nodes in the same layer. ///// If v is the left neighbor of w, then Gў has an edge f = e(v,w) with d( f ) = r(v,w) and ///// w( f ) = 0. This edge forces the nodes to be sufficiently ///// separated but does not affect the cost of the layout. XLayoutGraph CreateXLayoutGraph(LayerArrays layerArrays) { int nOfVerts = properLayeredGraph.NodeCount; //create edges of XLayoutGraph var edges = new List<IntEdge>(); foreach (LayerEdge e in properLayeredGraph.Edges) { var n1 = new IntEdge(nOfVerts, e.Source); var n2 = new IntEdge(nOfVerts, e.Target); n1.Weight = n2.Weight = e.Weight; n1.Separation = 0; //these edge have 0 separation n2.Separation = 0; nOfVerts++; edges.Add(n1); edges.Add(n2); } foreach (var layer in layerArrays.Layers) for (int i = layer.Length - 1; i > 0; i--) { int source = layer[i]; int target = layer[i - 1]; var ie = new IntEdge(source, target); Anchor sourceAnchor = database.Anchors[source]; Anchor targetAnchor = database.Anchors[target]; double sep = sourceAnchor.LeftAnchor + targetAnchor.RightAnchor + sugiyamaSettings.NodeSeparation; ie.Separation = (int) (sep + 1); edges.Add(ie); } var ret = new XLayoutGraph(IntGraph, properLayeredGraph, layerArrays, edges, nOfVerts); ret.SetEdgeWeights(); return ret; }
void InsertVirtualEdgesIfNeeded(LayerArrays layerArrays) { if (constrainedOrdering != null) //if there are constraints we handle multiedges correctly return; foreach (var kv in database.Multiedges) // If there are an even number of multi-edges between two nodes then // add a virtual edge in the multi-edge dict to improve the placement, but only in case when the edge goes down only one layer. if (kv.Value.Count%2 == 0 && layerArrays.Y[kv.Key.First] - 1 == layerArrays.Y[kv.Key.Second]) { var newVirtualEdge = new IntEdge(kv.Key.First, kv.Key.Second); newVirtualEdge.Edge = new Edge(); newVirtualEdge.IsVirtualEdge = true; kv.Value.Insert(kv.Value.Count/2, newVirtualEdge); IntGraph.AddEdge(newVirtualEdge); } }
/// <summary> /// /// </summary> /// <returns>the height of the graph+spaceBeforeMargins</returns> internal static void CalcInitialYAnchorLocations(LayerArrays layerArrays, double spaceBeforeMargins, GeometryGraph originalGraph, Database database, BasicGraph<IntEdge> intGraph, SugiyamaLayoutSettings settings, bool layersAreDoubled) { Anchor[] anchors = database.Anchors; double ymax = originalGraph.Margins + spaceBeforeMargins; //setting up y coord - going up by y-layers int i = 0; foreach (var yLayer in layerArrays.Layers) { double bottomAnchorMax = 0; double topAnchorMax = 0; foreach (int j in yLayer) { Anchor p = anchors[j]; if (p.BottomAnchor > bottomAnchorMax) bottomAnchorMax = p.BottomAnchor; if (p.TopAnchor > topAnchorMax) topAnchorMax = p.TopAnchor; } MakeVirtualNodesTall(yLayer, bottomAnchorMax, topAnchorMax, originalGraph.Nodes.Count, database.Anchors); double flatEdgesHeight = SetFlatEdgesForLayer(database, layerArrays, i, intGraph, settings, ymax); double layerCenter = ymax + bottomAnchorMax + flatEdgesHeight; double layerTop = layerCenter + topAnchorMax; if (NeedToSnapTopsToGrid(settings)) { layerTop += SnapDeltaUp(layerTop, settings.GridSizeByY); foreach (int j in yLayer) anchors[j].Top = layerTop; } else if (NeedToSnapBottomsToGrid(settings)) { double layerBottom = layerCenter - bottomAnchorMax; layerBottom += SnapDeltaUp(layerBottom, layerBottom); foreach (int j in yLayer) { anchors[j].Bottom = layerBottom; layerTop = Math.Max(anchors[j].Top, layerTop); } } else foreach (int j in yLayer) anchors[j].Y = layerCenter; double layerSep = settings.ActualLayerSeparation(layersAreDoubled); ymax = layerTop + layerSep; i++; } // for the last layer SetFlatEdgesForLayer(database, layerArrays, i, intGraph, settings, ymax); }
void OrderLayers(LayerArrays layerArrays) { foreach (var layer in layerArrays.Layers) OrderLayerBasedOnRecoveredXCoords(layer); }
void AnalyzeNeedToInsertLayersAndHasMultiedges(LayerArrays layerArrays, ref bool needToInsertLayers, ref bool multipleEdges) { foreach (IntEdge ie in IntGraph.Edges) if (ie.HasLabel && layerArrays.Y[ie.Source] != layerArrays.Y[ie.Target]) { //if an edge is a flat edge then needToInsertLayers = true; break; } if (needToInsertLayers == false && constrainedOrdering == null) //if we have constrains the multiple edges have been already represented in layers foreach (var kv in database.Multiedges) if (kv.Value.Count > 1) { multipleEdges = true; if (layerArrays.Y[kv.Key.x] - layerArrays.Y[kv.Key.y] == 1) { //there is a multi edge spanning exactly one layer; unfortunately we need to introduce virtual vertices for //the edges middle points needToInsertLayers = true; break; } } }
/// <summary> /// Sort new odd layers by the sum of x-coordinatates of predecessors and the successors of /// dummy nodes. /// </summary> void SortNewOddLayers() { for (int i = 1; i < nla.Layers.Length; i += 2) { SortedDictionary<int, object> sd = new SortedDictionary<int, object>(); 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<int> l = new List<int>(); l.Add((int)o); l.Add(v); sd[x] = l; } else { List<int> l = o as List<int>; 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<int>) layer[c++] = k; } } //update X now for (int m = 0; m < layer.Length; m++) nla.X[layer[m]] = m; } } /// <summary> /// Allocating new layering and filling its y-layers /// </summary> void InitNewLayering() { nla = new LayerArrays(new int[totalNodes]); for (int i = 0; i < layeredGraph.NodeCount; i++) NLayering[i] = la.Y[i] * 2; foreach (KeyValuePair<IntPair, List<IntEdge>> 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; }
public RecoveryLayerCalculator(LayerArrays recoveredLayerArrays) { layers = recoveredLayerArrays; }
/* void CalculateXPositionsWithQP(LayerArrays layerArrays){ ISolverShell solver = ConstrainedOrdering.CreateSolver(); foreach (var layer in layerArrays.Layers) AddNotOverlappingConstraints(layer, solver); foreach (var list in database.Multiedges.Values) foreach (IntEdge edge in list) AddEdgeToSolverTarget(edge, solver, edge.Weight); int j = -1; for (int i = 0; i < intGraph.Nodes.Count; i++) if(intGraph.OutEdgesCount(i) != 0 || intGraph.InEdgesCount(i) != 0){ j = i; break; } if(j != -1){ for (int i = 0; i < intGraph.Nodes.Count; i++) if(intGraph.OutEdgesCount(i) == 0 && intGraph.InEdgesCount(i) == 0) solver.AddGoalTwoVariablesAreClose(i, j); } j = 0; foreach (Anchor a in database.Anchors) a.X = solver.GetVariableResolvedPosition(j++); } */ void DecideIfUsingFastXCoordCalculation(LayerArrays layerArrays) { if (layerArrays.X.Length >= sugiyamaSettings.BrandesThreshold) Brandes = true; #if !SILVERLIGHT && !SHARPKIT else { string s = Environment.GetEnvironmentVariable("Brandes"); if (!String.IsNullOrEmpty(s) && String.Compare(s, "on", true, CultureInfo.CurrentCulture) == 0) Brandes = true; } #endif }
/// <summary> /// The function calculates y-layers and x-layers, /// thus, in fact, defining node, including dummy nodes, locations. /// </summary> /// <param name="layerArrays"></param> void CalculateXLayersByGansnerNorth(LayerArrays layerArrays) { xLayoutGraph = CreateXLayoutGraph(layerArrays); CalculateXLayersByGansnerNorthOnProperLayeredGraph(); }
/// <summary> /// /// </summary> static internal void CalculateXCoordinates(LayerArrays layerArrays, ProperLayeredGraph layeredGraph, int nOfOriginalVs, Anchor[] anchors, double nodeSeparation) { XCoordsWithAlignment x = new XCoordsWithAlignment(layerArrays, layeredGraph, nOfOriginalVs, anchors, nodeSeparation); x.Calculate(); }
/// <summary> /// Reorder only points having identical nodePositions /// </summary> internal static void UpdateLayerArrays(ProperLayeredGraph properLayeredGraph, LayerArrays layerArrays, Dictionary <int, Point> nodePositions) { new MetroMapOrdering(properLayeredGraph, layerArrays, nodePositions).UpdateLayerArrays(); }
/// <summary> /// Reorder virtual nodes between the same pair of real nodes /// </summary> internal static void UpdateLayerArrays(ProperLayeredGraph properLayeredGraph, LayerArrays layerArrays) { Dictionary <int, Point> nodePositions = BuildInitialNodePositions(properLayeredGraph, layerArrays); UpdateLayerArrays(properLayeredGraph, layerArrays, nodePositions); }
///// <summary> ///// This method can be improved: see the paper Simple And Efficient ... ///// </summary> ///// <param name="graph"></param> ///// <param name="layerArrays"></param> ///// <param name="bottom">bottom of the strip</param> ///// <returns></returns> static int GetCrossingCountFromStrip(int bottom, ProperLayeredGraph properLayeredGraph, LayerArrays layerArrays) { int[] topVerts = layerArrays.Layers[bottom + 1]; int[] bottomVerts = layerArrays.Layers[bottom]; if (bottomVerts.Length <= topVerts.Length) { return(GetCrossingCountFromStripWhenBottomLayerIsShorter(bottomVerts, properLayeredGraph, layerArrays)); } else { return(GetCrossingCountFromStripWhenTopLayerIsShorter(topVerts, bottomVerts, properLayeredGraph, layerArrays)); } }
LayerArrays InsertLayersIfNeeded(LayerArrays layerArrays) { bool needToInsertLayers = false; bool multipleEdges = false; InsertVirtualEdgesIfNeeded(layerArrays); AnalyzeNeedToInsertLayersAndHasMultiedges(layerArrays, ref needToInsertLayers, ref multipleEdges); if (needToInsertLayers) { LayerInserter.InsertLayers(ref properLayeredGraph, ref layerArrays, database, IntGraph); LayersAreDoubled = true; } else if (multipleEdges) EdgePathsInserter.InsertPaths(ref properLayeredGraph, ref layerArrays, database, IntGraph); RecreateIntGraphFromDataBase(); return layerArrays; }
LayerArrays CalculateLayerArrays() { LayerArrays layerArrays = CalculateYLayers(); if (constrainedOrdering == null) { DecideIfUsingFastXCoordCalculation(layerArrays); CalculateAnchorsAndYPositions(layerArrays); if (Brandes) CalculateXPositionsByBrandes(layerArrays); else CalculateXLayersByGansnerNorth(layerArrays); } else anchors = database.Anchors; OptimizeEdgeLabelsLocations(); engineLayerArrays = layerArrays; StraightensShortEdges(); double aspectRatio; CalculateOriginalGraphBox(out aspectRatio); if (sugiyamaSettings.AspectRatio != 0) StretchToDesiredAspectRatio(aspectRatio, sugiyamaSettings.AspectRatio); return layerArrays; }
/// <summary> /// /// </summary> /// <returns>the height of the graph+spaceBeforeMargins</returns> internal static void CalcInitialYAnchorLocations(LayerArrays layerArrays, double spaceBeforeMargins, GeometryGraph originalGraph, Database database, BasicGraph<IntEdge> intGraph, SugiyamaLayoutSettings settings, bool layersAreDoubled) { Anchor[] anchors = database.Anchors; double ymax = originalGraph.Margins + spaceBeforeMargins; //setting up y coord - going up by y-layers int i = 0; foreach (var yLayer in layerArrays.Layers) { double bottomAnchorMax = 0; double topAnchorMax = 0; foreach (int j in yLayer) { Anchor p = anchors[j]; if (p.BottomAnchor > bottomAnchorMax) bottomAnchorMax = p.BottomAnchor; if (p.TopAnchor > topAnchorMax) topAnchorMax = p.TopAnchor; } MakeVirtualNodesHigh(yLayer, bottomAnchorMax, topAnchorMax, originalGraph.Nodes.Count, database.Anchors); double flatEdgesHeight = SetFlatEdgesForLayer(database, layerArrays, i, intGraph, settings, ymax); double y = ymax + bottomAnchorMax + flatEdgesHeight; foreach (int j in yLayer) anchors[j].Y = y; double layerSep = settings.ActualLayerSeparation(layersAreDoubled); ymax = y + topAnchorMax + layerSep; i++; } SetFlatEdgesForLayer(database, layerArrays, i, intGraph, settings, ymax); }
void CalculateAnchorsAndYPositions(LayerArrays layerArrays) { CalculateAnchorSizes(database, out anchors, properLayeredGraph, originalGraph, IntGraph, sugiyamaSettings); CalcInitialYAnchorLocations(layerArrays, 500, originalGraph, database, IntGraph, sugiyamaSettings, LayersAreDoubled); }
LayerArrays YLayeringAndOrdering(LayerCalculator layering) { #region reporting #if REPORTING Timer t = null; if (sugiyamaSettings.Reporting) { t = new Timer(); Report("ylayering ... "); t.Start(); } #endif #endregion int[] yLayers = layering.GetLayers(); Balancing.Balance(GluedDagSkeletonForLayering, yLayers, GetNodeCountsOfGluedDag(), null); yLayers = ExtendLayeringToUngluedSameLayerVertices(yLayers); #region reporting #if REPORTING if (sugiyamaSettings.Reporting) { t.Stop(); Report(String.Format(CultureInfo.CurrentCulture, "{0}\n", t.Duration)); Report("ordering ... "); t.Start(); } #endif #endregion var layerArrays = new LayerArrays(yLayers); //if (!SugiyamaSettings.UseEdgeBundling && (HorizontalConstraints == null || HorizontalConstraints.IsEmpty)) { if (HorizontalConstraints == null || HorizontalConstraints.IsEmpty) { layerArrays = YLayeringAndOrderingWithoutHorizontalConstraints(layerArrays); #region reporting #if REPORTING if (sugiyamaSettings.Reporting) { t.Stop(); Report(String.Format(CultureInfo.CurrentCulture, "{0}\n", t.Duration)); } #endif #endregion return layerArrays; } constrainedOrdering = new ConstrainedOrdering(originalGraph, IntGraph, layerArrays.Y, nodeIdToIndex, database, sugiyamaSettings); constrainedOrdering.Calculate(); properLayeredGraph = constrainedOrdering.ProperLayeredGraph; #region reporting #if REPORTING if (sugiyamaSettings.Reporting) { t.Stop(); Report(String.Format(CultureInfo.CurrentCulture, "{0}\n", t.Duration)); } #endif #endregion // SugiyamaLayoutSettings.ShowDatabase(this.database); return constrainedOrdering.LayerArrays; }
//[System.Diagnostics.Conditional("DEBUGGLEE")] //private void TestYXLayers(LayerArrays layerArrays, int[] xLayers) { // foreach (IntEdge e in this.xLayoutGraph.Edges) { // int s = e.Source; int targ = e.Target; // if (e.Source >= layeredGraph.Nodes.Count) { // if (xLayoutGraph.OutEdges(s).Count != 2 || xLayoutGraph.InEdges(s).Count != 0) // Report("must be two out edges and none incoming"); // if (targ >= layeredGraph.Nodes.Count) // Report("an illegal edge"); // } else { // if (layerArrays.Y[s] != layerArrays.Y[targ]) // Report("layers don't coincide"); // if (layerArrays.X[s] - 1 != layerArrays.X[targ]) // Report("wrong input"); // if (xLayers[s] <= xLayers[targ]) // Report("wrong xlayering"); // } // } //} /// <summary> /// Creating a proper layered graph, a graph where each /// edge goes only one layer down from the i+1-th layer to the i-th layer. /// </summary> /// <param name="layering"></param> /// <param name="layerArrays"></param> void CreaeteProperLayeredGraph(int[] layering, out LayerArrays layerArrays) { int n = layering.Length; int nOfVV = 0; foreach (IntEdge e in database.SkeletonEdges()) { int span = EdgeSpan(layering, e); Debug.Assert(span >= 0); if (span > 0) e.LayerEdges = new LayerEdge[span]; int pe = 0; //offset in the string if (span > 1) { //we create span-2 dummy nodes and span new edges int d0 = n + nOfVV++; var layerEdge = new LayerEdge(e.Source, d0, e.CrossingWeight,e.Weight); e.LayerEdges[pe++] = layerEdge; //create span-2 internal edges all from dummy nodes for (int j = 0; j < span - 2; j++) { d0++; nOfVV++; layerEdge = new LayerEdge(d0 - 1, d0, e.CrossingWeight,e.Weight); e.LayerEdges[pe++] = layerEdge; } layerEdge = new LayerEdge(d0, e.Target, e.CrossingWeight, e.Weight); e.LayerEdges[pe] = layerEdge; } else if (span == 1) { var layerEdge = new LayerEdge(e.Source, e.Target, e.CrossingWeight, e.Weight); e.LayerEdges[pe] = layerEdge; } } var extendedVertexLayering = new int[originalGraph.Nodes.Count + nOfVV]; foreach (IntEdge e in database.SkeletonEdges()) if (e.LayerEdges != null) { int l = layering[e.Source]; extendedVertexLayering[e.Source] = l--; foreach (LayerEdge le in e.LayerEdges) extendedVertexLayering[le.Target] = l--; } else { extendedVertexLayering[e.Source] = layering[e.Source]; extendedVertexLayering[e.Target] = layering[e.Target]; } properLayeredGraph = new ProperLayeredGraph(new BasicGraph<Node, IntEdge>(database.SkeletonEdges(), layering.Length)); properLayeredGraph.BaseGraph.Nodes = IntGraph.Nodes; layerArrays = new LayerArrays(extendedVertexLayering); }
LayerArrays YLayeringAndOrderingWithoutHorizontalConstraints(LayerArrays layerArrays) { CreaeteProperLayeredGraph(layerArrays.Y, out layerArrays); Ordering.OrderLayers(properLayeredGraph, layerArrays, originalGraph.Nodes.Count, sugiyamaSettings.AspectRatio != 0, sugiyamaSettings, CancelToken); MetroMapOrdering.UpdateLayerArrays(properLayeredGraph, layerArrays); return layerArrays; }
void CalculateXPositionsByBrandes(LayerArrays layerArrays) { XCoordsWithAlignment.CalculateXCoordinates(layerArrays, properLayeredGraph, originalGraph.Nodes.Count, database.Anchors, sugiyamaSettings.NodeSeparation); }
protected override void RunInternal() { #if DEBUGORDERING if (graph.NumberOfVertices != layering.Length) { throw new System.Exception("the layering does not correspond to the graph"); } foreach (IntEdge e in graph.Edges) { if (layering[e.Source] - layering[e.Target] != 1) { throw new System.Exception("the edge in the graph does not span exactly one layer:" + e); } } #endif #if PPC // Parallel -- susanlwo LayerArrays secondLayers = null; Ordering revOrdering = null; System.Threading.Tasks.Task t = null; if (/*orderingMeasure.x>0 &&*/ tryReverse) { secondLayers = layerArrays.ReversedClone(); revOrdering = new Ordering(properLayeredGraph.ReversedClone(), false, secondLayers, startOfVirtNodes, balanceVirtAndOrigNodes, this.hasCrossWeights, settings); // note: below we need to pass the CancelToken from this thread into the new thread, to make sure a previous thread from the ThreadPool's // thread static token (that may be in a cancelled state) is picked up. t = System.Threading.Tasks.Task.Factory.StartNew(() => revOrdering.Run(this.CancelToken)); } Calculate(); if (/*orderingMeasure.x>0 &&*/ tryReverse) { t.Wait(); if (revOrdering.measure < measure) { for (int j = 0; j < nOfLayers; j++) { secondLayers.Layers[j].CopyTo(layerArrays.Layers[nOfLayers - 1 - j], 0); } layerArrays.UpdateXFromLayers(); } } #else Calculate(); if (/*orderingMeasure.x>0 &&*/ tryReverse) { LayerArrays secondLayers = layerArrays.ReversedClone(); var revOrdering = new Ordering(properLayeredGraph.ReversedClone(), false, secondLayers, startOfVirtNodes, balanceVirtAndOrigNodes, hasCrossWeights, settings); revOrdering.Run(); if (revOrdering.measure < measure) { for (int j = 0; j < nOfLayers; j++) { secondLayers.Layers[j].CopyTo(layerArrays.Layers[nOfLayers - 1 - j], 0); } layerArrays.UpdateXFromLayers(); } } #endif }