using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Microsoft.Msagl.Core.DataStructures; using Microsoft.Msagl.Core.Geometry; using Microsoft.Msagl.Core.Geometry.Curves; using Microsoft.Msagl.Core.GraphAlgorithms; using Microsoft.Msagl.Core.Layout; using Microsoft.Msagl.DebugHelpers; using SymmetricSegment = Microsoft.Msagl.Core.DataStructures.SymmetricTuple; namespace Microsoft.Msagl.Layout.LargeGraphLayout { /// /// class keeping a level info /// public class LgLevel { internal readonly Dictionary _railDictionary = new Dictionary(); internal Dictionary RailDictionary { get { return _railDictionary; } } internal readonly Dictionary> _railsOfEdges = new Dictionary>(); internal Set HighlightedRails = new Set(); internal readonly int ZoomLevel; readonly GeometryGraph _geomGraph; internal RTree _railTree = new RTree(); internal RTree RailTree { get { return _railTree; } } RTree _nodeInfoTree = new RTree(); internal readonly Dictionary> _orderedRailsOfEdges = new Dictionary>(); /// /// /// /// /// needed only for statistics internal LgLevel(int zoomLevel, GeometryGraph geomGraph) { _geomGraph = geomGraph; ZoomLevel = zoomLevel; } internal RTree NodeInfoTree { get { return _nodeInfoTree; } } internal void CreateEmptyRailTree() { _railTree = new RTree(); } //public void CreateRailTree() { // RailTree = new RTree( // RailDictionary.Values.Select(rail => new KeyValuePair(rail.BoundingBox, rail))); //} /// /// get endpoint tuples of all rails /// /// public List GetAllRailsEndpoints() { var endpts = new List(); Point p0, p1; foreach (var rail in _railTree.GetAllLeaves()) { if (rail.GetStartEnd(out p0, out p1)) { endpts.Add(new SymmetricSegment(p0, p1)); } } return endpts; } public List FetchOrCreateRailSequence(List path) { List rails = new List(); for (int i = 0; i < path.Count - 1; i++) { var rail = FindOrCreateRail(path[i], path[i + 1]); if (rail == null) continue; rails.Add(rail); } return rails; } public Rail FindOrCreateRail(Point s, Point t) { var p0 = s; var p1 = t; var t1 = new SymmetricSegment(p0, p1); Rail rail; if (RailDictionary.TryGetValue(t1, out rail)) return rail; var t2 = new SymmetricSegment(p1, p0); if (RailDictionary.TryGetValue(t2, out rail)) return rail; // no rail exists // roman: please check that this code really can be commented out and does need to be fixed instead /* * var q0 = VisGraph.GetPointOfVisGraphVertex(s); var q1 = VisGraph.GetPointOfVisGraphVertex(t); if (q0 == null || q1 == null) { //no visgraph vertex found } else { var edge = VisGraph.FindEdge(q0.Point, q1.Point); }*/ return CreateRail(p0, p1); } public Rail CreateRail(Point ep0, Point ep1) { var st = new SymmetricSegment(ep0, ep1); Rail rail; if (RailDictionary.TryGetValue(st, out rail)) { return rail; } var ls = new LineSegment(ep0, ep1); rail = new Rail(ls, ZoomLevel); RailTree.Add(rail.BoundingBox, rail); RailDictionary.Add(st, rail); return rail; } public Rail FindRail(Point s, Point t) { var p0 = s; var p1 = t; var ss = new SymmetricSegment(p1, p0); Rail rail; RailDictionary.TryGetValue(ss, out rail); return rail; } internal IEnumerable GetRailsIntersectingRect(Rectangle visibleRectange) { var ret = new Set(); foreach (var rail in _railTree.GetAllIntersecting(visibleRectange)) ret.Insert(rail); return ret; } internal List GetEdgesPassingThroughRail(Rail rail) { return (from kv in _railsOfEdges where kv.Value.Contains(rail) select kv.Key).ToList(); } public Rail RemoveRailFromRtree(Rail rail) { return _railTree.Remove(rail.BoundingBox, rail); } /// /// try adding single rail to dictionary /// /// /// true iff the rail does not belong to _railDictionary public bool AddRailToDictionary(Rail rail) { Point p0, p1; if (!rail.GetStartEnd(out p0, out p1)) return false; var st = new SymmetricSegment(p0, p1); if (!_railDictionary.ContainsKey(st)) { _railDictionary.Add(st, rail); return true; } return false; } public void AddRailToRtree(Rail rail) { Point p0, p1; if (!rail.GetStartEnd(out p0, out p1)) return; if (_railTree.Contains(new Rectangle(p0, p1), rail)) return; _railTree.Add(new Rectangle(p0, p1), rail); } public void RemoveRailFromDictionary(Rail rail) { Point p0, p1; if (!rail.GetStartEnd(out p0, out p1)) return; _railDictionary.Remove(new SymmetricSegment(p0, p1)); } internal bool PrintQuota(IEnumerable nodes, int NodeQuota, int RailQuota) { //Console.WriteLine("running stats "+nodes.Count()); tileTableForStatistic.Clear(); foreach (var rail in _railDictionary.Values) if (rail.ZoomLevel == ZoomLevel) CreateStatisticsForRail(rail); RunStatisticsForNodes(nodes); int maxVerticesPerTile = 0; int maxRailsPerTile = 0; foreach (var tileStatistic in tileTableForStatistic.Values) { if (maxRailsPerTile < tileStatistic.rails) maxRailsPerTile = tileStatistic.rails; if (maxVerticesPerTile < tileStatistic.vertices) maxVerticesPerTile = tileStatistic.vertices; } Console.WriteLine("max rails per tile {0}\n" + "max verts per tile {1}.\n", maxRailsPerTile, maxVerticesPerTile); if (maxVerticesPerTile <= NodeQuota && maxRailsPerTile <= RailQuota) return true; //if ( maxRailsPerTile <= RailQuota) return true; return false; } internal bool QuotaSatisfied(IEnumerable nodes, int NodeQuota, int RailQuota) { //Console.WriteLine("running stats "+nodes.Count()); tileTableForStatistic.Clear(); foreach (var rail in _railDictionary.Values) if (rail.ZoomLevel == ZoomLevel) CreateStatisticsForRail(rail); RunStatisticsForNodes(nodes); int maxVerticesPerTile = 0; int maxRailsPerTile = 0; foreach (var tileStatistic in tileTableForStatistic.Values) { if (maxRailsPerTile < tileStatistic.rails) maxRailsPerTile = tileStatistic.rails; if (maxVerticesPerTile < tileStatistic.vertices) maxVerticesPerTile = tileStatistic.vertices; } //if (maxVerticesPerTile <= NodeQuota && maxRailsPerTile <= RailQuota) return true; if ( maxRailsPerTile <= RailQuota) return true; Console.WriteLine("max rails per tile {0}\n" + "max verts per tile {1}.\n", maxRailsPerTile, maxVerticesPerTile); return false; } #region Statistics internal void RunLevelStatistics(IEnumerable nodes) { Console.WriteLine("running stats"); foreach (var rail in _railDictionary.Values) CreateStatisticsForRail(rail); RunStatisticsForNodes(nodes); double numberOfTiles = (double) ZoomLevel*ZoomLevel; double averageRailsForTile = 0; double averageVerticesForTile = 0; int maxVerticesPerTile = 0; int maxRailsPerTile = 0; int maxTotalPerTile = 0; foreach (var tileStatistic in tileTableForStatistic.Values) { averageVerticesForTile += tileStatistic.vertices/numberOfTiles; averageRailsForTile += tileStatistic.rails/numberOfTiles; if (maxRailsPerTile < tileStatistic.rails) maxRailsPerTile = tileStatistic.rails; if (maxVerticesPerTile < tileStatistic.vertices) maxVerticesPerTile = tileStatistic.vertices; if (maxTotalPerTile < tileStatistic.vertices + tileStatistic.rails) maxTotalPerTile = tileStatistic.vertices + tileStatistic.rails; } Console.WriteLine("level {0}: average rails per tile {1}\n" + "average verts per tile {2}, total average per tile {1}.\n", ZoomLevel, averageRailsForTile, averageVerticesForTile); Console.WriteLine("max rails per tile {0}\n" + "max verts per tile {1}, total max per tile {2}.\n", maxRailsPerTile, maxVerticesPerTile, maxTotalPerTile); Console.WriteLine("done with stats"); } void RunStatisticsForNodes(IEnumerable nodes) { foreach (var node in nodes) { CreateStatisticsForNode(node); } } void CreateStatisticsForNode(Node node) { foreach (var tile in GetCurveTiles(node.BoundaryCurve)) tile.vertices++; } void CreateStatisticsForRail(Rail rail) { var arrowhead = rail.Geometry as Arrowhead; if (arrowhead != null) CreateStatisticsForArrowhead(arrowhead); else foreach (var t in GetCurveTiles(rail.Geometry as ICurve)) t.rails++; } void CreateStatisticsForArrowhead(Arrowhead arrowhead) { TileStatistic tile = GetOrCreateTileStatistic(arrowhead.TipPosition); tile.rails++; } TileStatistic GetOrCreateTileStatistic(Point p) { Tuple t = DeviceIndependendZoomCalculatorForNodes.PointToTuple(_geomGraph.LeftBottom, p, GetGridSize()); TileStatistic ts; if (tileTableForStatistic.TryGetValue(t, out ts)) return ts; tileTableForStatistic[t] = ts = new TileStatistic {rails = 0, vertices = 0}; return ts; } IEnumerable GetCurveTiles(ICurve curve) { var tiles = new Set(); const int n = 64; var s = curve.ParStart; var e = curve.ParEnd; var d = (e - s)/(n - 1); for (int i = 0; i < 64; i++) { var t = s + i*d; var ts = GetOrCreateTileStatistic(curve[t]); tiles.Insert(ts); } return tiles; } class TileStatistic { public int vertices; public int rails; } readonly Dictionary, TileStatistic> tileTableForStatistic = new Dictionary, TileStatistic>(); double GetGridSize() { return Math.Max(_geomGraph.Width, _geomGraph.Height) / ZoomLevel; } #endregion internal void AddRail(Rail rail) { if (AddRailToDictionary(rail)) AddRailToRtree(rail); } public void ClearRailTree() { _railTree.Clear(); } public void CreateNodeTree(IEnumerable nodeInfos, double nodeDotWidth) { foreach (var n in nodeInfos) NodeInfoTree.Add(new RectangleNode(n, new Rectangle(new Size(nodeDotWidth, nodeDotWidth),n.Center))); } public IEnumerable GetNodesIntersectingRect(Rectangle visibleRectangle) { return NodeInfoTree.GetAllIntersecting(visibleRectangle).Select(n => n.GeometryNode); } public IEnumerable GetNodesIntersectingRectLabelzero(Rectangle visibleRectangle, double l) { var x = NodeInfoTree.GetAllIntersecting(visibleRectangle);//.Select(n => n.GeometryNode); List r = new List(); foreach (var y in x) { if(y.ZoomLevel <= l) r.Add(y.GeometryNode); } return r; } public bool RectIsEmptyOnLevel(Rectangle tileBox) { LgNodeInfo lg; return !NodeInfoTree.OneIntersecting(tileBox, out lg); } internal void RemoveFromRailEdges(List> removeList) { foreach (var symmetricTuple in removeList) RemoveTupleFromRailEdges(symmetricTuple); } void RemoveTupleFromRailEdges(SymmetricTuple tuple) { var a = tuple.A.GeometryNode; var b = tuple.B.GeometryNode; foreach (var edge in EdgesBetween(a, b)) _railsOfEdges.Remove(edge); } IEnumerable EdgesBetween(Node a, Node b) { foreach (var e in a.InEdges.Where(e => e.Source == b)) yield return e; foreach (var e in a.OutEdges.Where(e => e.Target == b)) yield return e; } } }