/// <summary> /// /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <param name="step"></param> /// <param name="baryCenter"></param> /// <param name="byRealPosition"></param> /// <returns>The index of the layer which is not ordered by <paramref name="baryCenter"/> anymore. /// If all of the layers ordered, and phase2 sweep done it returns with -1.</returns> protected int SugiyamaPhase2Sweep(int start, int end, int step, BaryCenter baryCenter, bool byRealPosition) { CrossCount crossCountDirection = baryCenter == BaryCenter.Up ? CrossCount.Up : CrossCount.Down; for (int i = start; i != end; i += step) { var layer = _layers[i]; //switch the vertices with the same barycenters, if and only if there will be less barycenters layer.Measure(baryCenter, byRealPosition); layer.FindBestPermutation(crossCountDirection); if (byRealPosition) { HorizontalPositionAssignmentOnLayer(i, baryCenter); CopyPositionsSilent(false); } else { CopyPositions(); } OnIterationEnded(" Phase 2 sweepstep finished [" + baryCenter + "-barycentering on layer " + i + "]"); if (i + step != end) { var nextLayer = _layers[i + step]; if (!nextLayer.IsOrderedByBaryCenters(baryCenter, byRealPosition)) { return(i + step); } } } return(-1); }
/// <summary> /// Computes the measures for every vertex in the layer by the given barycenters. /// </summary> /// <param name="baryCenters">The barycenters.</param> /// <param name="byRealPosition">If true, the barycenters will be computed based on the RealPosition.X value of the vertices. Otherwise the barycenter will be computed based on the value of the Position field (which is basically the index of the vertex inside the layer).</param> public void Measure(BaryCenter baryCenters, bool byRealPosition) { bool computeUpBaryCenter = (baryCenters & BaryCenter.Up) == BaryCenter.Up; bool computeDownBaryCenter = (baryCenters & BaryCenter.Down) == BaryCenter.Down; bool computeSubBaryCenter = (baryCenters & BaryCenter.Sub) == BaryCenter.Sub; int divCount = 0; if (computeUpBaryCenter) { divCount++; } if (computeDownBaryCenter) { divCount++; } if (computeSubBaryCenter) { divCount++; } //compute the measures for every vertex in the layer foreach (var vertex in this) { Measure(vertex, computeUpBaryCenter, computeDownBaryCenter, computeSubBaryCenter, divCount, byRealPosition); } }
protected void SugiyamaPhase2(out int unorderedLayerIndex, out BaryCenter baryCentering, bool byRealPosition) { //Sweeping up unorderedLayerIndex = SugiyamaPhase2Sweep(1, _layers.Count, 1, BaryCenter.Up, byRealPosition); if (unorderedLayerIndex != -1) { baryCentering = BaryCenter.Up; return; } //Sweeping down unorderedLayerIndex = SugiyamaPhase2Sweep(_layers.Count - 2, -1, -1, BaryCenter.Down, byRealPosition); baryCentering = BaryCenter.Down; }
/// <summary> /// Sweeps in one direction in the 1st Phase of the Sugiyama's algorithm. /// </summary> /// <param name="start">The index of the layer where the sweeping starts.</param> /// <param name="end">The index of the layer where the sweeping ends.</param> /// <param name="step">Stepcount.</param> /// <param name="baryCenter">Kind of the barycentering (Up/Down-barycenter).</param> /// <param name="dirty">If this is a dirty sweep</param> /// <param name="byRealPosition"></param> /// <returns></returns> protected bool SugiyamaPhase1Sweep(int start, int end, int step, BaryCenter baryCenter, bool dirty, bool byRealPosition) { bool hasOptimization = false; CrossCount crossCounting = baryCenter == BaryCenter.Up ? CrossCount.Up : CrossCount.Down; bool sourceByMeasure = crossCounting == CrossCount.Down; for (int i = start; i != end; i += step) { var layer = _layers[i]; int modifiedCrossing = 0; int originalCrossing = 0; if (!dirty) { //get the count of the edge crossings originalCrossing = layer.CalculateCrossCount(crossCounting); } //measure the vertices by the given barycenter layer.Measure(baryCenter, byRealPosition); if (!dirty) { //get the modified crossing count modifiedCrossing = layer.CalculateCrossCount(crossCounting, sourceByMeasure, !sourceByMeasure); } if (modifiedCrossing < originalCrossing || dirty) { layer.SortByMeasure(); hasOptimization = true; } if (byRealPosition) { HorizontalPositionAssignmentOnLayer(i, baryCenter); CopyPositionsSilent(false); } else { CopyPositions(); } OnIterationEnded(" Phase 1 sweepstep finished [" + baryCenter + "-barycentering on layer " + i + "]"); } return(hasOptimization); }
protected bool SugiyamaPhase1(int startLayerIndex, BaryCenter startBaryCentering, bool ByRealPosition) { if (_layers.Count < 2) { return(false); } const bool dirty = false; bool sweepDownOptimized = false; if (startBaryCentering == BaryCenter.Up) { sweepDownOptimized = SugiyamaPhase1Sweep(startLayerIndex == -1 ? 1 : startLayerIndex, _layers.Count, 1, BaryCenter.Up, dirty, ByRealPosition); startLayerIndex = -1; } bool sweepUpOptimized = SugiyamaPhase1Sweep(startLayerIndex == -1 ? _layers.Count - 2 : startLayerIndex, -1, -1, BaryCenter.Down, dirty, ByRealPosition); return(sweepUpOptimized || sweepDownOptimized); }
protected bool SugiyamaPhase2(out int unorderedLayerIndex, out BaryCenter baryCentering, bool byRealPosition, CancellationToken cancellationToken) { //Sweeping up unorderedLayerIndex = SugiyamaPhase2Sweep(1, _layers.Count, 1, BaryCenter.Up, byRealPosition, cancellationToken); if (unorderedLayerIndex != -1) { baryCentering = BaryCenter.Up; return(false); } //Sweeping down unorderedLayerIndex = SugiyamaPhase2Sweep(_layers.Count - 2, -1, -1, BaryCenter.Down, byRealPosition, cancellationToken); baryCentering = BaryCenter.Down; if (unorderedLayerIndex != -1) { return(false); } //Phase 2 done return(true); }
/// <summary> /// /// </summary> /// <param name="baryCenters"></param> /// <param name="byRealPosition"></param> /// <returns>Returns with true if the vertices in this /// layer ordered by the given <paramref name="baryCenters"/>.</returns> public bool IsOrderedByBaryCenters(BaryCenter baryCenters, bool byRealPosition) { if (Count == 0) { return(true); } //fill the measure by the given barycenters Measure(baryCenters, byRealPosition); //check that the ordering is valid for (int i = 1; i < Count; i++) { if (this[i].Measure < this[i - 1].Measure) { return(false); //invalid ordering } } //the ordering is valid return(true); }
protected void HorizontalPositionAssignmentSweep(int start, int end, int step, BaryCenter baryCenter) { for (int i = start; i != end; i += step) { HorizontalPositionAssignmentOnLayer(i, baryCenter); } }
protected void HorizontalPositionAssignmentOnLayer(int layerIndex, BaryCenter baryCenter) { var layer = _layers[layerIndex]; //compute where the vertices should be placed layer.Measure(baryCenter, true); layer.CalculateSubPriorities(); //set the RealPositions to NaN foreach (var v in layer) { v.RealPosition.X = float.NaN; } //set the positions in the order of the priorities, start with the lower priorities foreach (var v in from vertex in layer orderby vertex.Priority ascending, vertex.SubPriority ascending select vertex) { //first set the new position v.RealPosition.X = v.Measure; //check if there's any overlap between the actual vertex and the vertices which position has already been set SugiVertex v1 = v; var alreadySetVertices = layer.Where(vertex => (!double.IsNaN(vertex.RealPosition.X) && vertex != v1)).ToArray(); if (alreadySetVertices.Length == 0) { //there can't be any overlap continue; } //get the index of the 'v' vertex between the vertices which position has already been set int indexOfV; for (indexOfV = 0; indexOfV < alreadySetVertices.Length && alreadySetVertices[indexOfV].Position < v.Position; indexOfV++) { } SugiVertex leftNeighbor = null, rightNeighbor = null; double leftOverlap = 0, rightOverlap = 0; //check the overlap with vertex on the left if (indexOfV > 0) { leftNeighbor = alreadySetVertices[indexOfV - 1]; leftOverlap = CalculateOverlap(leftNeighbor, v); } if (indexOfV < alreadySetVertices.Length) { rightNeighbor = alreadySetVertices[indexOfV]; rightOverlap = CalculateOverlap(v, rightNeighbor); } // ReSharper disable PossibleNullReferenceException //only one neighbor overlaps if (leftOverlap > 0 && rightOverlap == 0) { if (leftNeighbor.Priority == v.Priority) { double leftMove = leftOverlap * 0.5; if (rightNeighbor != null) { rightOverlap = CalculateOverlap(v, rightNeighbor, leftMove); } leftNeighbor.RealPosition.X -= leftMove; v.RealPosition.X += leftMove; if (rightOverlap > 0) { if (v.Priority == rightNeighbor.Priority) { double rightMove = rightOverlap * 0.5; rightNeighbor.RealPosition.X += rightMove; v.RealPosition.X -= rightMove; leftNeighbor.RealPosition.X -= rightMove; } else { rightNeighbor.RealPosition.X += rightOverlap; } } } else { leftNeighbor.RealPosition.X -= leftOverlap; } } else if (leftOverlap == 0 && rightOverlap > 0) { if (v.Priority == rightNeighbor.Priority) { double rightMove = rightOverlap * 0.5; if (leftNeighbor != null) { leftOverlap = CalculateOverlap(leftNeighbor, v, rightMove); } rightNeighbor.RealPosition.X += rightMove; v.RealPosition.X -= rightMove; if (leftOverlap > 0) { if (leftNeighbor.Priority == v.Priority) { double leftMove = leftOverlap * 0.5; leftNeighbor.RealPosition.X -= leftMove; v.RealPosition.X += leftMove; rightNeighbor.RealPosition.X += leftMove; } else { leftNeighbor.RealPosition.X -= leftOverlap; } } } else { rightNeighbor.RealPosition.X += rightOverlap; } } else if (leftOverlap > 0 && rightOverlap > 0) { //if both neighbor overlapped //priorities equals, 1 priority lower, 2 priority lower if (leftNeighbor.Priority < v.Priority && v.Priority == rightNeighbor.Priority) { double rightMove = rightOverlap * 0.5; rightNeighbor.RealPosition.X += rightMove; v.RealPosition.X -= rightMove; leftNeighbor.RealPosition.X -= (leftOverlap + rightMove); } else if (leftNeighbor.Priority == v.Priority && v.Priority > rightNeighbor.Priority) { double leftMove = leftOverlap * 0.5; leftNeighbor.RealPosition.X -= leftMove; v.RealPosition.X += leftMove; rightNeighbor.RealPosition.X = (rightOverlap + leftMove); } else { //priorities of the neighbors are lower, or equal leftNeighbor.RealPosition.X -= leftOverlap; rightNeighbor.RealPosition.X += rightOverlap; } } // ReSharper restore PossibleNullReferenceException //the vertices on the left side of the leftNeighbor will be moved, if they overlap if (leftOverlap > 0) { for (int index = indexOfV - 1; index > 0 && (leftOverlap = CalculateOverlap(alreadySetVertices[index - 1], alreadySetVertices[index])) > 0; index--) { alreadySetVertices[index - 1].RealPosition.X -= leftOverlap; } } //the vertices on the right side of the rightNeighbor will be moved, if they overlap if (rightOverlap > 0) { for (int index = indexOfV; index < alreadySetVertices.Length - 1 && (rightOverlap = CalculateOverlap(alreadySetVertices[index], alreadySetVertices[index + 1])) > 0; index++) { alreadySetVertices[index + 1].RealPosition.X += rightOverlap; } } } }
protected void SugiyamaLayout() { bool baryCenteringByRealPositions = Parameters.PositionCalculationMethod == PositionCalculationMethodTypes.PositionBased; if (Parameters.DirtyRound) { //start with a dirty round (sort by barycenters, even if the number of the crossings will rise) SugiyamaDirtyPhase(baryCenteringByRealPositions); } bool changed = true; int iteration1Left = Parameters.Phase1IterationCount; int iteration2Left = Parameters.Phase2IterationCount; double maxIterations = iteration1Left * iteration2Left; int startLayerIndex = -1; BaryCenter startBaryCentering = BaryCenter.Up; while (changed && (iteration1Left > 0 || iteration2Left > 0)) { changed = false; // // Phase 1 - while there's any optimization // while (iteration1Left > 0 && SugiyamaPhase1(startLayerIndex, startBaryCentering, baryCenteringByRealPositions)) { iteration1Left--; changed = true; } startLayerIndex = -1; startBaryCentering = BaryCenter.Up; // // Phase 2 // if (iteration2Left > 0) { SugiyamaPhase2(out startLayerIndex, out startBaryCentering, baryCenteringByRealPositions); iteration2Left--; } // Phase fallback if (startLayerIndex != -1) { iteration1Left = Parameters.Phase1IterationCount; changed = true; } _statusInPercent += PercentOfSugiyama / maxIterations; } #region Mark the neighbour vertices connected with associative edges foreach (SugiEdge e in _graph.GeneralEdges) { int sourceIndex = _layers[e.Source.LayerIndex].IndexOf(e.Source); int targetIndex = _layers[e.Target.LayerIndex].IndexOf(e.Target); bool shouldBeMarked = e.Source.LayerIndex == e.Target.LayerIndex && Math.Abs(sourceIndex - targetIndex) == 1; if (shouldBeMarked) { if (sourceIndex < targetIndex) { e.Source.RightGeneralEdgeCount += 1; e.Target.LeftGeneralEdgeCount += 1; } else { e.Target.RightGeneralEdgeCount += 1; e.Source.LeftGeneralEdgeCount += 1; } } } #endregion }