// 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.Layout; // using Microsoft.Msagl.DebugHelpers; // namespace Microsoft.Msagl.Routing.Spline.Bundling { // // Linear algorithm as described in our paper // // Edge Routing with Ordered Bunldles // // < // public class LinearMetroMapOrdering : GeneralMetroMapOrdering { // // bundle lines // // < // readonly Array < Metroline > MetrolinesGlobal; // Array < int[] > Metrolines; // // Station positions // // < // Point[] positions; // // Initialize bundle graph and build the ordering // // < // internal LinearMetroMapOrdering(Array < Metroline > MetrolinesGlobal, Map < Point, Station > pointToIndex) { // this.MetrolinesGlobal = MetrolinesGlobal; // ConvertParameters(pointToIndex); // BuildOrder(); // } // // Get the ordering of lines on station u with respect to the edge (u->v) // // < // Array < Metroline > GeneralMetroMapOrdering.GetOrder(Station u, Station v) { // MetroEdge me = MetroEdge.CreateFromTwoNodes(u.SerialNumber, v.SerialNumber); // Array < int > orderedMetrolineListForUv = order[me]; // if (u.SerialNumber < v.SerialNumber) { // foreach(int MetrolineIndex of orderedMetrolineListForUv) // yield return MetrolinesGlobal[MetrolineIndex]; // } // else { // for (int i = orderedMetrolineListForUv.Count - 1; i >= 0; i--) // yield return MetrolinesGlobal[orderedMetrolineListForUv[i]]; // } // } // // Get the index of line on the edge (u->v) and node u // // < // int GeneralMetroMapOrdering.GetLineIndexInOrder(Station u, Station v, Metroline Metroline) { // MetroEdge me = MetroEdge.CreateFromTwoNodes(u.SerialNumber, v.SerialNumber); // Map < Metroline, int > d = lineIndexInOrder[me]; // if (u.SerialNumber < v.SerialNumber) { // return d[Metroline]; // } // else { // return d.Count - 1 - d[Metroline]; // } // } // void ConvertParameters(Map < Point, Station > pointToIndex) { // Metrolines = new Array(); // positions = new Point[pointToIndex.Count]; // foreach(Metroline gline of MetrolinesGlobal) { // Array < int > line = new Array(); // foreach(Point p of gline.Polyline) { // line.Add(pointToIndex[p].SerialNumber); // positions[pointToIndex[p].SerialNumber] = p; // } // Metrolines.Add(line.ToArray()); // } // } // //order for node u of edge u->v // Map < MetroEdge, Array < int >> order; // Map < MetroEdge, Map < Metroline, int >> lineIndexInOrder; // HashSet < int > nonTerminals; // HashSet < MetroEdge > initialEdges; // // Edge in graph H // // label is used to distinguish multiple edges // // < // class MetroEdge { // Array nodes; // internal static MetroEdge CreateFromTwoNodes(int u, int v) { // MetroEdge res = new MetroEdge(); // res.nodes = new Array(); // res.nodes.Add(Math.Min(u, v)); // res.nodes.Add(Math.Max(u, v)); // #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 // res.UpdateHashKey(); // #endif // return res; // } // internal static MetroEdge CreateFromTwoEdges(int v, MetroEdge e1, MetroEdge e2) { // int s = e1.Source() === v ? e1.Target() : e1.Source(); // int t = e2.Source() === v ? e2.Target() : e2.Source(); // if (s < t) // return CreateFromTwoEdges(v, e1.nodes, e2.nodes); // else // return CreateFromTwoEdges(v, e2.nodes, e1.nodes); // } // internal static MetroEdge CreateFromTwoEdges(int v, Array e1, Array < int > e2) { // Array < int > nodes = new Array(e1.Count + e2.Count - 1); // if (e1[0] !== v) { // for (int i = 0; i < e1.Count; i++) // nodes.Add(e1[i]); // } // else { // for (int i = e1.Count - 1; i >= 0; i--) // nodes.Add(e1[i]); // } // if (e2[0] === v) { // for (int i = 1; i < e2.Count; i++) // nodes.Add(e2[i]); // } // else { // for (int i = e2.Count - 2; i >= 0; i--) // nodes.Add(e2[i]); // } // MetroEdge res = new MetroEdge(); // res.nodes = nodes; // #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 // res.UpdateHashKey(); // #endif // return res; // } // internal int Source() { // return nodes[0]; // } // internal int Target() { // return nodes[nodes.Count - 1]; // } // public override string ToString() { // string s = "("; // foreach(int i of nodes) // s += i + " "; // s += ")"; // return s; // } // int label; // bool labelCached = false; // #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 Support Map directly based on object's GetHashCode // private SharpKit.JavaScript.JsString _hashKey; // private void UpdateHashKey() // { // _hashKey = GetHashCode().ToString(); // } // #endif // public override int GetHashCode() // { // if (!labelCached) { // ulong hc = (ulong)nodes.Count; // for (int i = 0; i < nodes.Count; i++) { // hc = unchecked(hc * 314159 + (ulong)nodes[i]); // } // label = (int)hc; // labelCached = true; // } // return label; // } // // overrides the equality // // < // public override bool Equals(object obj) { // if (!(obj is MetroEdge)) // return false; // return (MetroEdge)obj === this; // } // public static bool operator === (MetroEdge pair0, MetroEdge pair1) { // if (pair0.GetHashCode() !== pair1.GetHashCode()) return false; // return true; // //TODO: are conflicts possible? // //return pair0.nodes.SequenceEqual(pair1.nodes); // } // public static bool operator !== (MetroEdge pair0, MetroEdge pair1) { // return !(pair0 === pair1); // } // } // // unordered list of paths on a specified edge // // < // class PathList { // internal MetroEdge edge; // internal HashSet paths; // internal Array subLists; // public override string ToString() { // return edge.ToString() + " (" + paths.Count + ")"; // } // } // class PathOnEdge { // internal int index; // internal LinkedListNode node; // public override string ToString() { // string s = "(index = " + index + ")"; // return s; // } // } // Map < int, LinkedList < MetroEdge >> orderedAdjacent; // Map < Tuple < int, MetroEdge >, LinkedListNode < MetroEdge >> adjacencyIndex; // Map < MetroEdge, PathList > e2p; // Map < int, LinkedList < MetroEdge >> paths; // // Do the main job // // < // void BuildOrder() { // //init local structures // Initialize(); // //ordering itself // foreach(int v of nonTerminals) { // ProcessNonTerminal(v); // } // //get result // RestoreResult(); // } // void Initialize() { // //non terminals and adjacent // nonTerminals = new HashSet(); // initialEdges = new HashSet(); // //non-sorted adjacent edges. will be sorted later // Map < int, HashSet < MetroEdge >> adjacent = new Map>(); // for (int mi = 0; mi < Metrolines.Count; mi++) { // int[] Metroline = Metrolines[mi]; // for (int i = 0; i + 1 < Metroline.length; i++) { // MetroEdge me = MetroEdge.CreateFromTwoNodes(Metroline[i], Metroline[i + 1]); // if (!initialEdges.Contains(me)) // initialEdges.Add(me); // if (i + 2 < Metroline.length) // nonTerminals.Add(Metroline[i + 1]); // CollectionUtilities.AddToMap(adjacent, Metroline[i], me); // CollectionUtilities.AddToMap(adjacent, Metroline[i + 1], me); // } // } // //order neighbors around each vertex // InitAdjacencyData(adjacent); // //create e2p and paths... // InitPathData(); // } // void InitPathData() { // paths = new Map>(); // e2p = new Map(); // for (int mi = 0; mi < Metrolines.Count; mi++) { // int[] Metroline = Metrolines[mi]; // paths.Add(mi, new LinkedList()); // for (int i = 0; i + 1 < Metroline.length; i++) { // MetroEdge me = MetroEdge.CreateFromTwoNodes(Metroline[i], Metroline[i + 1]); // if (!e2p.ContainsKey(me)) { // PathList pl = new PathList(); // pl.edge = me; // pl.paths = new HashSet(); // e2p.Add(me, pl); // } // PathOnEdge pathOnEdge = new PathOnEdge(); // pathOnEdge.index = mi; // pathOnEdge.node = paths[mi].AddLast(me); // e2p[me].paths.Add(pathOnEdge); // } // } // } // void InitAdjacencyData(Map < int, HashSet < MetroEdge >> adjacent) { // orderedAdjacent = new Map>(); // adjacencyIndex = new Map, LinkedListNode>(); // foreach(int v of adjacent.Keys) { // Array < MetroEdge > adj = new Array(adjacent[v]); // orderedAdjacent.Add(v, SortAdjacentEdges(v, adj)); // } // } // LinkedList < MetroEdge > SortAdjacentEdges(int v, Array < MetroEdge > adjacent) { // MetroEdge mn = adjacent.First(); // int mnv = OppositeNode(mn, v); // adjacent.Sort(delegate(MetroEdge edge1, MetroEdge edge2) { // int a = OppositeNode(edge1, v); // int b = OppositeNode(edge2, v); // //TODO: remove angles! // double angA = Point.Angle(positions[a] - positions[v], positions[mnv] - positions[v]); // double angB = Point.Angle(positions[b] - positions[v], positions[mnv] - positions[v]); // return angA.CompareTo(angB); // }); // LinkedList < MetroEdge > res = new LinkedList(); // foreach(MetroEdge edge of adjacent) { // LinkedListNode < MetroEdge > node = res.AddLast(edge); // adjacencyIndex.Add(new Tuple(v, edge), node); // } // return res; // } // // update adjacencies of node 'a': put new edges instead of oldEdge // // < // void UpdateAdjacencyData(int a, MetroEdge oldEdge, Array < PathList > newSubList) { // //find a (cached) position of oldEdge in order // LinkedListNode < MetroEdge > node = adjacencyIndex[new Tuple(a, oldEdge)]; // Assert.assert(node.Value === oldEdge); // LinkedListNode < MetroEdge > inode = node; // foreach(PathList pl of newSubList) { // MetroEdge newEdge = pl.edge; // if (oldEdge.Source() === a) // node = node.Array.AddAfter(node, newEdge); // else // node = node.Array.AddBefore(node, newEdge); // adjacencyIndex.Add(new Tuple(a, newEdge), node); // } // adjacencyIndex.Remove(new Tuple(a, oldEdge)); // inode.Array.Remove(inode); // } // // recursively build an order on the edge // // < // Array < int > RestoreResult(MetroEdge edge) { // Array < int > res = new Array(); // PathList pl = e2p[edge]; // if (pl.subLists == null ) { // foreach(PathOnEdge path of pl.paths) // res.Add(path.index); // } // else { // foreach(PathList subList of pl.subLists) { // Array < int > subResult = RestoreResult(subList.edge); // if (!(edge.Source() === subList.edge.Source() || edge.Target() === subList.edge.Target())) // subResult.Reverse(); // res.AddRange(subResult); // } // } // return res; // } // void RestoreResult() { // order = new Map>(); // lineIndexInOrder = new Map>(); // foreach(MetroEdge me of initialEdges) { // order.Add(me, RestoreResult(me)); // Map < Metroline, int > d = new Map(); // int index = 0; // foreach(int v of order[me]) { // d[MetrolinesGlobal[v]] = index++; // } // lineIndexInOrder.Add(me, d); // } // } // // Remove vertex v from the graph. Update graph and paths correspondingly // // < // void ProcessNonTerminal(int v) { // //oldEdge => sorted PathLists // Map < MetroEdge, Array < PathList >> newSubLists = RadixSort(v); // //update current data // foreach(MetroEdge oldEdge of orderedAdjacent[v]) { // Assert.assert(e2p.ContainsKey(oldEdge)); // Array < PathList > newSubList = newSubLists[oldEdge]; // //update e2p[oldEdge] // e2p[oldEdge].paths = null; // e2p[oldEdge].subLists = newSubList; // //update ordered adjacency data // UpdateAdjacencyData(OppositeNode(oldEdge, v), oldEdge, newSubList); // //update paths and add new edges // foreach(PathList pl of newSubList) { // MetroEdge newEdge = pl.edge; // //we could check the reverse edge before // if (e2p.ContainsKey(newEdge)) continue; // //add e2p for new edge // e2p.Add(newEdge, pl); // //update paths // foreach(PathOnEdge path of pl.paths) { // UpdatePath(path, v, newEdge); // } // } // } // } // // Linear sorting of paths passing through vertex v // // < // Map < MetroEdge, Array < PathList >> RadixSort(int v) { // //build a map [old_edge => list_of_paths_on_it]; the relative order of paths is important // Map < MetroEdge, Array < PathOnEdge >> r = new Map>(); // //first index in circular order // Map < MetroEdge, int > firstIndex = new Map(); // foreach(MetroEdge oldEdge of orderedAdjacent[v]) { // PathList pathList = e2p[oldEdge]; // foreach(PathOnEdge path of pathList.paths) { // MetroEdge ej = FindNextEdgeOnPath(v, path); // CollectionUtilities.AddToMap(r, ej, path); // } // firstIndex.Add(oldEdge, (r.ContainsKey(oldEdge) ? r[oldEdge].Count : 0)); // } // //oldEdge => SortedPathLists // Map < MetroEdge, Array < PathList >> res = new Map>(); // //build the desired order for each edge // foreach(MetroEdge oldEdge of orderedAdjacent[v]) { // //r[oldEdge] is the right order! (up to the circleness) // Array < PathOnEdge > paths = r[oldEdge]; // Assert.assert(paths.Count > 0); // Array < PathList > subLists = new Array(); // HashSet < PathOnEdge > curPathSet = new HashSet(); // for (int j = 0; j < paths.Count; j++) { // int i = (j + firstIndex[oldEdge]) % paths.Count; // MetroEdge nowEdge = paths[i].node.Value; // MetroEdge nextEdge = paths[(i + 1) % paths.Count].node.Value; // curPathSet.Add(paths[i]); // if (j === paths.Count - 1 || nowEdge !== nextEdge) { // //process // MetroEdge newEdge = MetroEdge.CreateFromTwoEdges(v, oldEdge, nowEdge); // PathList pl = new PathList(); // pl.edge = newEdge; // pl.paths = curPathSet; // subLists.Add(pl); // //clear // curPathSet = new HashSet(); // } // } // if (oldEdge.Source() === v) subLists.Reverse(); // res.Add(oldEdge, subLists); // } // return res; // } // // extract the next edge on a given path after node v // // < // MetroEdge FindNextEdgeOnPath(int v, PathOnEdge pathOnEdge) { // if (pathOnEdge.node.next != null) { // int o = OppositeNode(pathOnEdge.node.next.Value, v); // if (o !== -1) return pathOnEdge.node.next.Value; // } // if (pathOnEdge.node.Previous != null) { // int o = OppositeNode(pathOnEdge.node.Previous.Value, v); // if (o !== -1) return pathOnEdge.node.Previous.Value; // } // throw new NotSupportedException(); // } // // return an opposite vertex of a given edge // // < // int OppositeNode(MetroEdge edge, int v) { // if (edge.Source() === v) return edge.Target(); // if (edge.Target() === v) return edge.Source(); // return -1; // } // // replace edges (av) and (vb) with edge (ab) on a given path // // < // void UpdatePath(PathOnEdge pathOnEdge, int v, MetroEdge newEdge) { // LinkedListNode < MetroEdge > f = pathOnEdge.node; // Assert.assert(f.Value.Source() === v || f.Value.Target() === v); // int a, b; // a = OppositeNode(f.Value, v); // if (f.next != null && (b = OppositeNode(f.next.Value, v)) !== -1) { // Assert.assert((a === newEdge.Source() || a === newEdge.Target())); // Assert.assert((b === newEdge.Source() || b === newEdge.Target())); // f.Value = newEdge; // f.Array.Remove(f.next); // } // else if (f.Previous != null && (b = OppositeNode(f.Previous.Value, v)) !== -1) { // Assert.assert((a === newEdge.Source() || a === newEdge.Target())); // Assert.assert((b === newEdge.Source() || b === newEdge.Target())); // f.Value = newEdge; // f.Array.Remove(f.Previous); // } // else // throw new NotSupportedException(); // } // } // }