internal ConstrainedOrdering( GeometryGraph geomGraph, BasicGraph<Node, IntEdge> basicIntGraph, int[] layering, Dictionary<Node, int> nodeIdToIndex, Database database, SugiyamaLayoutSettings settings) { this.settings = settings; horizontalConstraints = settings.HorizontalConstraints; horizontalConstraints.PrepareForOrdering(nodeIdToIndex, layering); geometryGraph = geomGraph; this.database = database; intGraph = basicIntGraph; initialLayering = layering; //this has to be changed only to insert layers that are needed if (NeedToInsertLayers(layering)) { for (int i = 0; i < layering.Length; i++) layering[i] *= 2; LayersAreDoubled = true; numberOfLayers = -1; } PrepareProperLayeredGraphAndFillLayerInfos(); adjSwapper = new AdjacentSwapsWithConstraints( LayerArrays, HasCrossWeights(), ProperLayeredGraph, layerInfos); }
internal PhyloTreeLayoutCalclulation(PhyloTree phyloTreeP, SugiyamaLayoutSettings settings, BasicGraph<Node, IntEdge> intGraphP, Database dataBase) { this.dataBase = dataBase; this.tree = phyloTreeP; this.LayoutSettings = settings; this.intGraph = intGraphP; originalNodeToGridLayerIndices = new int[intGraph.Nodes.Count]; }
/// <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; }
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(); }
/// <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(); }
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; }
/// <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; }
static double WidthOfSelfEdge(Database database, int i, ref double rightAnchor, ref double topAnchor, ref double bottomAnchor, SugiyamaLayoutSettings settings) { double delta = 0; List<IntEdge> multiedges = database.GetMultiedge(i, i); //it could be a multiple self edge if (multiedges.Count > 0) { foreach (IntEdge e in multiedges) if (e.Edge.Label != null) { rightAnchor += e.Edge.Label.Width; if (topAnchor < e.Edge.Label.Height/2.0) topAnchor = bottomAnchor = e.Edge.Label.Height/2.0f; } delta += (settings.NodeSeparation + settings.MinNodeWidth)*multiedges.Count; } return delta; }
void CreateDatabaseAndRegisterIntEdgesInMultiEdges() { Database = new Database(); foreach (IntEdge e in IntGraph.Edges) database.RegisterOriginalEdgeInMultiedges(e); }
static void CalcAnchorsForOriginalNode(int i, BasicGraph<Node, IntEdge> intGraph, Anchor[] anchors, Database database, SugiyamaLayoutSettings settings) { double leftAnchor = 0; double rightAnchor = leftAnchor; double topAnchor = 0; double bottomAnchor = topAnchor; //that's what we would have without the label and multiedges if (intGraph.Nodes != null) { Node node = intGraph.Nodes[i]; ExtendStandardAnchors(ref leftAnchor, ref rightAnchor, ref topAnchor, ref bottomAnchor, node, settings); } RightAnchorMultiSelfEdges(i, ref rightAnchor, ref topAnchor, ref bottomAnchor, database, settings); double hw = settings.MinNodeWidth/2; if (leftAnchor < hw) leftAnchor = hw; if (rightAnchor < hw) rightAnchor = hw; double hh = settings.MinNodeHeight/2; if (topAnchor < hh) topAnchor = hh; if (bottomAnchor < hh) bottomAnchor = hh; anchors[i] = new Anchor(leftAnchor, rightAnchor, topAnchor, bottomAnchor, intGraph.Nodes[i], settings.LabelCornersPreserveCoefficient) {Padding = intGraph.Nodes[i].Padding}; #if TEST_MSAGL anchors[i].UserData = intGraph.Nodes[i].UserData; #endif }
static void RightAnchorMultiSelfEdges(int i, ref double rightAnchor, ref double topAnchor, ref double bottomAnchor, Database database, SugiyamaLayoutSettings settings) { double delta = WidthOfSelfEdge(database, i, ref rightAnchor, ref topAnchor, ref bottomAnchor, settings); rightAnchor += delta; }
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; }
static double SetFlatEdgesLabelsHeightAndPositionts(IntPair pair, double ymax, double dy, Database database) { double height = 0; List<IntEdge> list = database.GetMultiedge(pair); foreach (IntEdge edge in list) { height += dy; Label label = edge.Edge.Label; if (label != null) { label.Center = new Point(label.Center.X, ymax + height + label.Height/2); height += label.Height; } } return height; }
/// <summary> /// Simpler constructor which initializes the internal graph representation automatically /// </summary> /// <param name="originalGraph"></param> /// <param name="settings"></param> internal LayeredLayoutEngine(GeometryGraph originalGraph, SugiyamaLayoutSettings settings) { if (originalGraph != null) { //enumerate the nodes - maps node indices to strings nodeIdToIndex = new Dictionary<Node, int>(); IList<Node> nodes = originalGraph.Nodes; int index = 0; foreach (Node n in nodes) { nodeIdToIndex[n] = index; index++; } var edges = originalGraph.Edges; var intEdges = new IntEdge[edges.Count]; int i = 0; foreach(var edge in edges){ if (edge.Source == null || edge.Target == null) throw new InvalidOperationException(); //"creating an edge with null source or target"); var intEdge = new IntEdge(nodeIdToIndex[edge.Source], nodeIdToIndex[edge.Target], edge); intEdges[i] = intEdge; i++; } IntGraph = new BasicGraph<Node, IntEdge>(intEdges, originalGraph.Nodes.Count) {Nodes = nodes}; this.originalGraph = originalGraph; sugiyamaSettings = settings; Database = new Database(); foreach (IntEdge e in IntGraph.Edges) database.RegisterOriginalEdgeInMultiedges(e); CycleRemoval(); } }
/// <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); }
internal static void CalculateAnchorSizes(Database database, out Anchor[] anchors, ProperLayeredGraph properLayeredGraph, GeometryGraph originalGraph, BasicGraph<Node, IntEdge> intGraph, SugiyamaLayoutSettings settings) { database.Anchors = anchors = new Anchor[properLayeredGraph.NodeCount]; for (int i = 0; i < anchors.Length; i++) anchors[i] = new Anchor(settings.LabelCornersPreserveCoefficient); //go over the old vertices for (int i = 0; i < originalGraph.Nodes.Count; i++) CalcAnchorsForOriginalNode(i, intGraph, anchors, database, settings); //go over virtual vertices foreach (IntEdge intEdge in database.AllIntEdges) if (intEdge.LayerEdges != null) { foreach (LayerEdge layerEdge in intEdge.LayerEdges) { int v = layerEdge.Target; if (v != intEdge.Target) { Anchor anchor = anchors[v]; if (!database.MultipleMiddles.Contains(v)) { anchor.LeftAnchor = anchor.RightAnchor = VirtualNodeWidth/2.0f; anchor.TopAnchor = anchor.BottomAnchor = VirtualNodeHeight(settings)/2.0f; } else { anchor.LeftAnchor = anchor.RightAnchor = VirtualNodeWidth*4; anchor.TopAnchor = anchor.BottomAnchor = VirtualNodeHeight(settings)/2.0f; } } } //fix label vertices if (intEdge.HasLabel) { int lj = intEdge.LayerEdges[intEdge.LayerEdges.Count/2].Source; Anchor a = anchors[lj]; double w = intEdge.LabelWidth, h = intEdge.LabelHeight; a.RightAnchor = w; a.LeftAnchor = VirtualNodeWidth*8; if (a.TopAnchor < h/2.0) a.TopAnchor = a.BottomAnchor = h/2.0; a.LabelToTheRightOfAnchorCenter = true; } } }
/// <summary> /// constructor /// </summary> internal LayeredLayoutEngine(GeometryGraph originalGraph, BasicGraph<Node, IntEdge> graph, Dictionary<Node, int> nodeIdToIndex, SugiyamaLayoutSettings settings) { if (originalGraph != null) { this.originalGraph = originalGraph; sugiyamaSettings = settings; IntGraph = graph; Database = new Database(); this.nodeIdToIndex = nodeIdToIndex; foreach (IntEdge e in graph.Edges) database.RegisterOriginalEdgeInMultiedges(e); #if REPORTING if (sugiyamaSettings.Reporting && SugiyamaLayoutLogger == null) SugiyamaLayoutLogger = new SugiyamaLayoutLogger(); #endif CycleRemoval(); } }
/// <summary> /// displays the database /// </summary> /// <param name="db"></param> /// <param name="curves"></param> public static void ShowDataBase(Database db, params ICurve[] curves){ var g = new Graph(""); AllocateDebugCurves(g); var graphBox = new Rectangle(db.Anchors[0].LeftTop); var cl = new List<ICurve>(curves); foreach (Anchor a in db.Anchors){ graphBox.Add(a.LeftTop); graphBox.Add(a.RightBottom); cl.Add(a.PolygonalBoundary); } AddCurvesToGraph(cl, g); Point del = (graphBox.LeftBottom - graphBox.RightTop)/10; graphBox.Add(graphBox.LeftBottom + del); graphBox.Add(graphBox.RightTop - del); var gg = new GeometryGraph{BoundingBox = graphBox}; g.DataBase = db; g.GeometryGraph = gg; DisplayGraph(g, new Form()); db.nodesToShow = null; }
/// <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); }
///// <summary> ///// mark the vertex as one representing a label ///// or a middle of a multi edge ///// </summary> ///// <param name="db"></param> ///// <param name="bucket"></param> ///// <param name="parent"></param> ///// <param name="i"></param> 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); } }