Example #1
0
        /// <summary>
        /// It computes the layout of the vertices.
        /// </summary>
        public override void Compute(CancellationToken cancellationToken)
        {
            if (VisitedGraph.VertexCount == 1)
            {
                VertexPositions.Add(VisitedGraph.Vertices.First(), new Point(0, 0));
                return;
            }

            //initializing the positions
            if (Parameters is BoundedFRLayoutParameters)
            {
                var param = Parameters as BoundedFRLayoutParameters;
                InitializeWithRandomPositions(param.Width, param.Height);
                _maxWidth  = param.Width;
                _maxHeight = param.Height;
            }
            else
            {
                InitializeWithRandomPositions(1000.0, 1000.0);
            }
            Parameters.VertexCount = VisitedGraph.VertexCount;

            // Actual temperature of the 'mass'. Used for cooling.
            var minimalTemperature = Parameters.InitialTemperature * 0.01;

            _temperature = Parameters.InitialTemperature;
            for (int i = 0;
                 i < Parameters._iterationLimit &&
                 _temperature > minimalTemperature;
                 i++)
            {
                IterateOne(cancellationToken);

                //make some cooling
                switch (Parameters._coolingFunction)
                {
                case FRCoolingFunction.Linear:
                    _temperature *= (1.0 - i / (double)Parameters._iterationLimit);
                    break;

                case FRCoolingFunction.Exponential:
                    _temperature *= Parameters._lambda;
                    break;
                }

                //iteration ended, do some report

                /*if (ReportOnIterationEndNeeded)
                 * {
                 *  double statusInPercent = (double)i / (double)Parameters._iterationLimit;
                 *  OnIterationEnded(i, statusInPercent, string.Empty, true);
                 * }*/
            }
        }
Example #2
0
        public override void Compute(CancellationToken cancellationToken)
        {
            if (VisitedGraph.VertexCount == 1)
            {
                if (!VertexPositions.ContainsKey(VisitedGraph.Vertices.First()))
                {
                    VertexPositions.Add(VisitedGraph.Vertices.First(), new Point(0, 0));
                }
                return;
            }

            //initialize vertex positions
            InitializeWithRandomPositions(Parameters.Width, Parameters.Height);

            //initialize ISOM data
            foreach (var vertex in VisitedGraph.Vertices)
            {
                ISOMData isomData;
                if (!_isomDataDict.TryGetValue(vertex, out isomData))
                {
                    isomData = new ISOMData();
                    _isomDataDict[vertex] = isomData;
                }
            }

            _radius = Parameters.InitialRadius;
            var rnd = new Random(Parameters.Seed);

            for (var epoch = 0; epoch < Parameters.MaxEpoch; epoch++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                Adjust(cancellationToken, rnd);

                //Update Parameters
                var factor = Math.Exp(-1 * Parameters.CoolingFactor * (1.0 * epoch / Parameters.MaxEpoch));
                _adaptation = Math.Max(Parameters.MinAdaption, factor * Parameters.InitialAdaption);
                if (_radius > Parameters.MinRadius && epoch % Parameters.RadiusConstantTime == 0)
                {
                    _radius--;
                }

                //report

                /*if ( ReportOnIterationEndNeeded )
                 *      OnIterationEnded( epoch, (double)epoch / (double)Parameters.MaxEpoch, "Iteration " + epoch + " finished.", true );
                 * else if (ReportOnProgressChangedNeeded)
                 * OnProgressChanged( (double)epoch / (double)Parameters.MaxEpoch * 100 );*/
            }
        }
        public override void Compute(CancellationToken cancellationToken)
        {
            VertexPositions.Clear();
            var bounds       = _parameters == null ? new RandomLayoutAlgorithmParams().Bounds : _parameters.Bounds;
            var boundsWidth  = (int)bounds.Width;
            var boundsHeight = (int)bounds.Height;
            var seed         = _parameters == null?Guid.NewGuid().GetHashCode() : _parameters.Seed;

            var rnd = new Random(seed);

            foreach (var item in VisitedGraph.Vertices)
            {
                if (item.SkipProcessing != ProcessingOptionEnum.Freeze || VertexPositions.Count == 0)
                {
                    var x    = (int)bounds.X;
                    var y    = (int)bounds.Y;
                    var size = VertexSizes.FirstOrDefault(a => a.Key == item).Value;
                    VertexPositions.Add(item,
                                        new Point(rnd.Next(x, x + boundsWidth - (int)size.Width),
                                                  rnd.Next(y, y + boundsHeight - (int)size.Height)));
                }
            }
        }
Example #4
0
        public override void Compute(CancellationToken cancellationToken)
        {
            if (VisitedGraph.VertexCount == 1)
            {
                VertexPositions.Add(VisitedGraph.Vertices.First(), new Point(0, 0));
                return;
            }

            #region Initialization
            _distances       = new double[VisitedGraph.VertexCount, VisitedGraph.VertexCount];
            _edgeLengths     = new double[VisitedGraph.VertexCount, VisitedGraph.VertexCount];
            _springConstants = new double[VisitedGraph.VertexCount, VisitedGraph.VertexCount];
            _vertices        = new TVertex[VisitedGraph.VertexCount];
            _positions       = new Point[VisitedGraph.VertexCount];

            //initializing with random positions
            InitializeWithRandomPositions(Parameters.Width, Parameters.Height);

            //copy positions into array (speed-up)
            int index = 0;
            foreach (var v in VisitedGraph.Vertices)
            {
                _vertices[index]  = v;
                _positions[index] = VertexPositions[v];
                index++;
            }

            //calculating the diameter of the graph
            //TODO check the diameter algorithm
            _diameter = VisitedGraph.GetDiameter <TVertex, TEdge, TGraph>(out _distances);

            //L0 is the length of a side of the display area
            double l0 = Math.Min(Parameters.Width, Parameters.Height);

            //ideal length = L0 / max d_i,j
            _idealEdgeLength = (l0 / _diameter) * Parameters.LengthFactor;

            //calculating the ideal distance between the nodes
            for (int i = 0; i < VisitedGraph.VertexCount - 1; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();
                for (int j = i + 1; j < VisitedGraph.VertexCount; j++)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    //distance between non-adjacent vertices
                    double dist = _diameter * Parameters.DisconnectedMultiplier;

                    //calculating the minimal distance between the vertices
                    if (_distances[i, j] != double.MaxValue)
                    {
                        dist = Math.Min(_distances[i, j], dist);
                    }
                    if (_distances[j, i] != double.MaxValue)
                    {
                        dist = Math.Min(_distances[j, i], dist);
                    }
                    _distances[i, j]       = _distances[j, i] = dist;
                    _edgeLengths[i, j]     = _edgeLengths[j, i] = _idealEdgeLength * dist;
                    _springConstants[i, j] = _springConstants[j, i] = Parameters.K / Math.Pow(dist, 2);
                }
            }
            #endregion

            int n = VisitedGraph.VertexCount;
            if (n == 0)
            {
                return;
            }

            //TODO check this condition
            for (int currentIteration = 0; currentIteration < Parameters.MaxIterations; currentIteration++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                #region An iteration
                double maxDeltaM = double.NegativeInfinity;
                int    pm        = -1;

                //get the 'p' with the max delta_m
                for (int i = 0; i < n; i++)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    double deltaM = CalculateEnergyGradient(i);
                    if (maxDeltaM < deltaM)
                    {
                        maxDeltaM = deltaM;
                        pm        = i;
                    }
                }
                //TODO is needed?
                if (pm == -1)
                {
                    return;
                }

                //calculating the delta_x & delta_y with the Newton-Raphson method
                //there is an upper-bound for the while (deltaM > epsilon) {...} cycle (100)
                for (int i = 0; i < 100; i++)
                {
                    _positions[pm] += CalcDeltaXY(pm);

                    double deltaM = CalculateEnergyGradient(pm);
                    //real stop condition
                    if (deltaM < double.Epsilon)
                    {
                        break;
                    }
                }

                //what if some of the vertices would be exchanged?
                if (Parameters.ExchangeVertices && maxDeltaM < double.Epsilon)
                {
                    double energy = CalcEnergy();
                    for (int i = 0; i < n - 1; i++)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        for (int j = i + 1; j < n; j++)
                        {
                            cancellationToken.ThrowIfCancellationRequested();

                            double xenergy = CalcEnergyIfExchanged(i, j);
                            if (energy > xenergy)
                            {
                                Point p = _positions[i];
                                _positions[i] = _positions[j];
                                _positions[j] = p;
                                return;
                            }
                        }
                    }
                }
                #endregion

                /* if ( ReportOnIterationEndNeeded )
                 *   Report( currentIteration );*/
            }
            Report(Parameters.MaxIterations);
        }
Example #5
0
        public override void Compute(CancellationToken cancellationToken)
        {
            var groups   = _params.GroupParametersList.Select(a => a.GroupId).OrderByDescending(a => a).ToList();
            var listRect = new Dictionary <object, Rect>();

            foreach (var group in groups)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var groupId = group;
                var gp      = _params.GroupParametersList.First(a => a.GroupId == groupId);
                //get vertices of the same group
                //var vertices = new List<TVertex>();
                var vertices = VisitedGraph.Vertices.Where(a => a.GroupId == groupId).ToList();
                //skip processing if there are no vertices in this group
                if (vertices.Count == 0)
                {
                    continue;
                }
                //get edges between vertices in the same group
                var edges = VisitedGraph.Edges.Where(a => a.Source.GroupId == a.Target.GroupId && a.Target.GroupId == groupId).ToList();
                //create and compute graph for a group
                var graph = GenerateGroupGraph(vertices, edges);
                //inject custom vertex and edge set into existing algorithm
                gp.LayoutAlgorithm.ResetGraph(graph.Vertices, graph.Edges);

                //assign vertex sizes to internal algorithm if needed
                if (gp.LayoutAlgorithm.NeedVertexSizes)
                {
                    gp.LayoutAlgorithm.VertexSizes = VertexSizes.Where(a => a.Key.GroupId == groupId)
                                                     .ToDictionary(a => a.Key, b => b.Value);
                }
                gp.LayoutAlgorithm.Compute(cancellationToken);

                //Move vertices to bound box if layout algorithm don't use bounds
                if (gp.ZoneRectangle.HasValue && !gp.IsAlgorithmBounded)
                {
                    var offsetX = gp.ZoneRectangle.Value.X;
                    var offsetY = gp.ZoneRectangle.Value.Y;
                    gp.LayoutAlgorithm.VertexPositions.ForEach(a =>
                    {
                        a.Value.Offset(offsetX, offsetY);
                    });
                }

                //write results to global positions storage
                double?[] left   = { null };
                double?[] top    = { null };
                double?[] right  = { null };
                double?[] bottom = { null };
                gp.LayoutAlgorithm.VertexPositions.ForEach(a =>
                {
                    left[0]   = left[0].HasValue ? (a.Value.X < left[0] ? a.Value.X : left[0]) : a.Value.X;
                    var w     = a.Value.X + VertexSizes[a.Key].Width;
                    var h     = a.Value.Y + VertexSizes[a.Key].Height;
                    right[0]  = right[0].HasValue ? (w > right[0] ? w : right[0]) : w;
                    top[0]    = top[0].HasValue ? (a.Value.Y < top[0] ? a.Value.Y : top[0]) : a.Value.Y;
                    bottom[0] = bottom[0].HasValue ? (h > bottom[0] ? h : bottom[0]) : h;

                    if (VertexPositions.ContainsKey(a.Key))
                    {
                        VertexPositions[a.Key] = a.Value;
                    }
                    else
                    {
                        VertexPositions.Add(a.Key, a.Value);
                    }
                });
                if (_params.ArrangeGroups)
                {
                    if (left[0] == null)
                    {
                        left[0] = 0;
                    }
                    if (right[0] == null)
                    {
                        right[0] = 0;
                    }
                    if (top[0] == null)
                    {
                        top[0] = 0;
                    }
                    if (bottom[0] == null)
                    {
                        bottom[0] = 0;
                    }
                    listRect.Add(gp.GroupId, gp.ZoneRectangle ?? new Rect(new Point(left[0].Value, top[0].Value), new Point(right[0].Value, bottom[0].Value)));
                }
            }

            if (_params.ArrangeGroups)
            {
                cancellationToken.ThrowIfCancellationRequested();
                var origList = listRect.ToDictionary(a => a.Key, a => a.Value);
                var ora      = _params != null && _params.OverlapRemovalAlgorithm != null ? _params.OverlapRemovalAlgorithm : new FSAAlgorithm <object>(listRect, new OverlapRemovalParameters {
                    HorizontalGap = 10, VerticalGap = 10
                });
                ora.Initialize(listRect);
                ora.Compute(cancellationToken);
                cancellationToken.ThrowIfCancellationRequested();
                ora.Rectangles.ForEach(a =>
                {
                    int group = (int)a.Key;
                    //_params.GroupParametersList.FirstOrDefault(b => b.GroupId == (int)a.Key).ZoneRectangle = origList[a.Key];
                    ArrangeRectangle(a.Value, group, origList[a.Key]);
                });
            }
        }
        public override void Compute(CancellationToken cancellationToken)
        {
            switch (VisitedGraph.VertexCount)
            {
            case 0:
                return;

            case 1:
                VertexPositions.Add(VisitedGraph.Vertices.First(), new Point(0, 0));
                return;
            }

            InitializeWithRandomPositions(1, 1, -0.5, -0.5);

            InitAlgorithm();

            var finalRepuExponent = Parameters.repulsiveExponent;
            var finalAttrExponent = Parameters.attractionExponent;

            for (var step = 1; step <= Parameters.iterationCount; step++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                ComputeBaryCenter();
                var quadTree = BuildQuadTree();

                #region hûlési függvény meghatározása
                if (Parameters.iterationCount >= 50 && finalRepuExponent < 1.0)
                {
                    Parameters.attractionExponent = finalAttrExponent;
                    Parameters.repulsiveExponent  = finalRepuExponent;
                    if (step <= 0.6 * Parameters.iterationCount)
                    {
                        // use energy model with few local minima
                        Parameters.attractionExponent += 1.1 * (1.0 - finalRepuExponent);
                        Parameters.repulsiveExponent  += 0.9 * (1.0 - finalRepuExponent);
                    }
                    else if (step <= 0.9 * Parameters.iterationCount)
                    {
                        // gradually move to final energy model
                        Parameters.attractionExponent +=
                            1.1 * (1.0 - finalRepuExponent) * (0.9 - step / (double)Parameters.iterationCount) / 0.3;
                        Parameters.repulsiveExponent +=
                            0.9 * (1.0 - finalRepuExponent) * (0.9 - step / (double)Parameters.iterationCount) / 0.3;
                    }
                }
                #endregion

                #region Move each node
                for (var i = 0; i < _vertices.Length; i++)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var v         = _vertices[i];
                    var oldEnergy = GetEnergy(i, quadTree);

                    // compute direction of the move of the node
                    Vector bestDir;
                    GetDirection(i, quadTree, out bestDir);

                    // line search: compute length of the move
                    var oldPos = v.Position;

                    var bestEnergy   = oldEnergy;
                    var bestMultiple = 0;
                    bestDir /= 32;
                    //kisebb mozgatások esetén a legjobb eset meghatározása
                    for (var multiple = 32;
                         multiple >= 1 && (bestMultiple == 0 || bestMultiple / 2 == multiple);
                         multiple /= 2)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        v.Position = oldPos + bestDir * multiple;
                        var curEnergy = GetEnergy(i, quadTree);
                        if (curEnergy < bestEnergy)
                        {
                            bestEnergy   = curEnergy;
                            bestMultiple = multiple;
                        }
                    }

                    //nagyobb mozgatás esetén van-e jobb megoldás?
                    for (var multiple = 64;
                         multiple <= 128 && bestMultiple == multiple / 2;
                         multiple *= 2)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        v.Position = oldPos + bestDir * multiple;
                        var curEnergy = GetEnergy(i, quadTree);
                        if (curEnergy < bestEnergy)
                        {
                            bestEnergy   = curEnergy;
                            bestMultiple = multiple;
                        }
                    }

                    //legjobb megoldással mozgatás
                    v.Position = oldPos + bestDir * bestMultiple;
                    if (bestMultiple > 0)
                    {
                        quadTree.MoveNode(oldPos, v.Position, v.RepulsionWeight);
                    }
                }
                #endregion

                /*if ( ReportOnIterationEndNeeded )
                 *      Report( step );*/
            }
            CopyPositions();
            NormalizePositions();
        }
        public override void Compute(CancellationToken cancellationToken)
        {
            //calculate the size of the circle
            double perimeter      = 0;
            var    usableVertices = VisitedGraph.Vertices.Where(v => v.SkipProcessing != ProcessingOptionEnum.Freeze).ToList();

            //if we have empty input positions list we have to fill positions for frozen vertices manualy
            if (VertexPositions.Count == 0)
            {
                foreach (var item in VisitedGraph.Vertices.Where(v => v.SkipProcessing == ProcessingOptionEnum.Freeze))
                {
                    VertexPositions.Add(item, new Point());
                }
            }
            double[] halfSize = new double[usableVertices.Count];
            int      i        = 0;

            foreach (var v in usableVertices)
            {
                cancellationToken.ThrowIfCancellationRequested();

                Size s = _sizes[v];
                halfSize[i] = Math.Sqrt(s.Width * s.Width + s.Height * s.Height) * 0.5;
                perimeter  += halfSize[i] * 2;
                i++;
            }

            double radius = perimeter / (2 * Math.PI);

            //
            //precalculation
            //
            double angle = 0, a;

            i = 0;
            foreach (var v in usableVertices)
            {
                cancellationToken.ThrowIfCancellationRequested();

                a      = Math.Sin(halfSize[i] * 0.5 / radius) * 2;
                angle += a;
                //if ( ReportOnIterationEndNeeded )
                VertexPositions[v] = new Point(Math.Cos(angle) * radius + radius, Math.Sin(angle) * radius + radius);
                angle += a;
            }

            //if ( ReportOnIterationEndNeeded )
            //    OnIterationEnded( 0, 50, "Precalculation done.", false );

            //recalculate radius
            radius = angle / (2 * Math.PI) * radius;

            //calculation
            angle = 0;
            i     = 0;
            foreach (var v in usableVertices)
            {
                cancellationToken.ThrowIfCancellationRequested();

                a      = Math.Sin(halfSize[i] * 0.5 / radius) * 2;
                angle += a;
                VertexPositions[v] = new Point(Math.Cos(angle) * radius + radius, Math.Sin(angle) * radius + radius);
                angle += a;
            }
        }