using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Microsoft.Msagl.Core.Geometry; using Microsoft.Msagl.Core.Geometry.Curves; using Microsoft.Msagl.Core.GraphAlgorithms; using Microsoft.Msagl.Core.Layout; namespace Microsoft.Msagl.Layout.Layered { /// /// An edge with source and target represented as integers, they point to an array of Nodes of the graph /// [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] #if TEST_MSAGL public #else internal #endif class IntEdge : IEnumerable, IEdge { int source; /// /// the source /// public int Source { get { return source; } #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 Support Dictionary directly based on object's GetHashCode set { source = value; UpdateHashKey(); } #else set { source = value; } #endif } int target; /// /// the edge target /// public int Target { get { return target; } #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 Support Dictionary directly based on object's GetHashCode set { target = value; UpdateHashKey(); } #else set { target = value; } #endif } bool reversed; /// /// An edge can be reversed to keep the graph acyclic /// public bool Reversed { get { return reversed; } // set { reversed = value; } } /// /// A dummy edge that will not be drawn; serves just as a place holder. /// public bool IsVirtualEdge { get; set; } /// /// constructor /// /// /// internal IntEdge(int source, int target) { this.source = source; this.target = target; #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 Support Dictionary directly based on object's GetHashCode UpdateHashKey(); #endif } /// /// Returns true if the edge has label /// internal bool HasLabel { get { return Edge.Label != null; } } /// /// Label width /// internal double LabelWidth { get { return Edge.Label.Width; } } /// /// Label height /// internal double LabelHeight { get { return Edge.Label.Height; } } /// /// This function changes the edge by swapping /// source and target. However Revert(Revert) does not change it. /// internal void Revert() { int t = source; source = target; target = t; reversed = !reversed; #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 Support Dictionary directly based on object's GetHashCode UpdateHashKey(); #endif } /// /// The original edge corresponding to the IntEdge /// public Edge Edge { get; set; } /// /// constructor /// /// /// /// internal IntEdge(int source, int target, Edge edge) { this.source = source; this.target = target; Edge = edge; if (edge != null) { Separation = edge.Separation; Weight = edge.Weight; } #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 Support Dictionary directly based on object's GetHashCode UpdateHashKey(); #endif } /// /// compares only source and target /// /// /// public override bool Equals(object obj) { var ie = obj as IntEdge; if (ie == null) return false; return ie.source == source && ie.target == target; } #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 Support Dictionary directly based on object's GetHashCode private SharpKit.JavaScript.JsString _hashKey; private void UpdateHashKey() { _hashKey = ""+source+","+target; } #endif /// /// /// /// public override int GetHashCode() { var hc = (uint) source.GetHashCode(); return (int) ((hc << 5 | hc >> 27) + (uint) target); } /// /// /// /// public override string ToString() { return "Edge(" + source + "->" + target + ")"; } internal ICurve Curve { get { return Edge.Curve; } set { Edge.Curve = value; } } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal SmoothedPolyline UnderlyingPolyline { get { return Edge.UnderlyingPolyline; } set { Edge.UnderlyingPolyline = value; } } int weight = 1; internal int Weight { get { return weight; } set { weight = value; } } int crossingWeight = 1; internal int CrossingWeight { get { return crossingWeight; } } int separation; /// /// the distance between the source and the target in the number of layers /// public int Separation { get { return separation; } set { separation = value; } } /// /// the edge span in layers /// public int LayerSpan { get { return layerEdges != null ? layerEdges.Length : 0; // return virtualStart == -1 ? 1 : VirtualEnd - VirtualStart + 2; } } LayerEdge[] layerEdges; /// /// /// #if TEST_MSAGL [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public #else internal #endif IList LayerEdges { get { return layerEdges; } set { layerEdges = (LayerEdge[]) value; } } internal bool SelfEdge() { return source == target; } internal IntEdge ReversedClone() { var ret = new IntEdge(target, source, Edge); if (layerEdges != null) { int len = layerEdges.Length; ret.layerEdges = new LayerEdge[len]; for (int i = 0; i < len; i++) { LayerEdge le = layerEdges[len - 1 - i]; ret.layerEdges[i] = new LayerEdge(le.Target, le.Source, le.CrossingWeight); } ret.layerEdges[0].Source = target; ret.layerEdges[layerEdges.Length - 1].Target = source; } #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=289 Support Dictionary directly based on object's GetHashCode ret.UpdateHashKey(); #endif return ret; } internal LayerEdge this[int i] { get { return layerEdges[i]; } } internal int Count { get { return layerEdges.Length; } } internal void UpdateEdgeLabelPosition(Anchor[] anchors) { if (Edge.Label != null) { int m = layerEdges.Length/2; LayerEdge layerEdge = layerEdges[m]; Routing.UpdateLabel(Edge, anchors[layerEdge.Source]); } } #region IEnumerable Members /// /// enumerates over virtual virtices corresponding to the original edge /// /// public IEnumerator GetEnumerator() { yield return layerEdges[0].Source; foreach (LayerEdge le in layerEdges) yield return le.Target; } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { yield return layerEdges[0].Source; foreach (LayerEdge le in layerEdges) yield return le.Target; } #endregion /// /// The function returns an array arr such that /// arr is a permutation of the graph vertices, /// and for any edge e in graph if e.Source=arr[i] /// e.Target=arr[j], then i is less than j /// /// /// internal static int[] GetOrder(BasicGraph graph){ var visited = new bool[graph.NodeCount]; //no recursion! So we have to organize a stack var sv = new Stack(); var se = new Stack>(); var order = new List(); IEnumerator en; for (int u = 0; u < graph.NodeCount; u++){ if (visited[u]) continue; int cu = u; visited[cu] = true; en = new Succ(graph, u).GetEnumerator(); do{ while (en.MoveNext()){ int v = en.Current; if (!visited[v]){ visited[v] = true; sv.Push(cu); se.Push(en); cu = v; en = new Succ(graph, cu).GetEnumerator(); } } order.Add(cu); if (sv.Count > 0){ en = se.Pop(); cu = sv.Pop(); } else break; } while (true); } order.Reverse(); return order.ToArray(); } } }