/// <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);
        }
Пример #2
0
            /// <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);
                }
            }
Пример #3
0
        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;
        }
Пример #4
0
        /// <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);
        }
Пример #7
0
            /// <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;
                    }
                }
            }
        }
Пример #10
0
        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
        }