/// <summary>
        /// Vertical offset rectangles.
        /// </summary>
        protected void Vertical()
        {
            WrappedRectangles.Sort(YComparison);
            int i = 0;
            int n = WrappedRectangles.Count;

            while (i < n)
            {
                // y_i = y_{i+1} = ... = y_k
                int k = i;
                RectangleWrapper <TObject> u = WrappedRectangles[i];
                for (int j = i; j < n; ++j)
                {
                    ThrowIfCancellationRequested();

                    RectangleWrapper <TObject> v = WrappedRectangles[j];
                    if (NearEqual(u.CenterY, v.CenterY))
                    {
                        u = v;
                        k = j;
                    }
                    else
                    {
                        break;
                    }
                }

                // delta = max(0, max{f.y(m,j)|i<=m<=k<j<n})
                double delta = 0;
                for (int m = i; m <= k; ++m)
                {
                    for (int j = k + 1; j < n; ++j)
                    {
                        ThrowIfCancellationRequested();

                        Vector force = Force2(WrappedRectangles[m].Rectangle, WrappedRectangles[j].Rectangle);
                        if (force.Y > delta)
                        {
                            delta = force.Y;
                        }
                    }
                }

                for (int j = k + 1; j < n; ++j)
                {
                    ThrowIfCancellationRequested();

                    RectangleWrapper <TObject> r = WrappedRectangles[j];
                    r.Rectangle.Offset(0, delta);
                }

                i = k + 1;
            }
        }
        /// <summary>
        /// Horizontal offset rectangles.
        /// </summary>
        protected void Horizontal()
        {
            WrappedRectangles.Sort(XComparison);
            int i = 0;
            int n = WrappedRectangles.Count;

            while (i < n)
            {
                // x_i = x_{i+1} = ... = x_k
                int k = i;
                RectangleWrapper <TObject> u = WrappedRectangles[i];
                for (int j = i + 1; j < n; ++j)
                {
                    ThrowIfCancellationRequested();

                    RectangleWrapper <TObject> v = WrappedRectangles[j];
                    if (NearEqual(u.CenterX, v.CenterX))
                    {
                        u = v;
                        k = j;
                    }
                    else
                    {
                        break;
                    }
                }

                // delta = max(0, max{f.x(m,j)|i<=m<=k<j<n})
                double delta = 0;
                for (int m = i; m <= k; ++m)
                {
                    for (int j = k + 1; j < n; ++j)
                    {
                        ThrowIfCancellationRequested();

                        Vector force = Force(WrappedRectangles[m].Rectangle, WrappedRectangles[j].Rectangle);
                        if (force.X > delta)
                        {
                            delta = force.X;
                        }
                    }
                }

                for (int j = k + 1; j < n; ++j)
                {
                    ThrowIfCancellationRequested();

                    RectangleWrapper <TObject> r = WrappedRectangles[j];
                    r.Rectangle.Offset(delta, 0);
                }

                i = k + 1;
            }
        }
        protected int XComparison([NotNull] RectangleWrapper <TObject> r1, [NotNull] RectangleWrapper <TObject> r2)
        {
            double r1CenterX = r1.CenterX;
            double r2CenterX = r2.CenterX;

            if (r1CenterX < r2CenterX)
            {
                return(-1);
            }
            if (r1CenterX > r2CenterX)
            {
                return(1);
            }
            return(0);
        }
        protected int YComparison(
            [NotNull] RectangleWrapper <TObject> r1,
            [NotNull] RectangleWrapper <TObject> r2)
        {
            double r1CenterY = r1.CenterY;
            double r2CenterY = r2.CenterY;

            if (r1CenterY < r2CenterY)
            {
                return(-1);
            }
            if (r1CenterY > r2CenterY)
            {
                return(1);
            }
            return(0);
        }
        /// <inheritdoc cref="FSAAlgorithm{TObject,TParameters}.HorizontalImproved"/>
        protected new double HorizontalImproved()
        {
            WrappedRectangles.Sort(XComparison);
            int i = 0;
            int n = WrappedRectangles.Count;

            // Left side
            RectangleWrapper <TObject> leftMin = WrappedRectangles[0];
            double sigma = 0;
            double x0    = leftMin.CenterX;
            var    gamma = new double[WrappedRectangles.Count];
            var    x     = new double[WrappedRectangles.Count];

            while (i < n)
            {
                RectangleWrapper <TObject> u = WrappedRectangles[i];

                // Rectangle with the same center than Rectangle[i]
                int k = i;
                for (int j = i + 1; j < n; ++j)
                {
                    ThrowIfCancellationRequested();

                    RectangleWrapper <TObject> v = WrappedRectangles[j];
                    if (NearEqual(u.CenterX, v.CenterX))
                    {
                        u = v;
                        k = j;
                    }
                    else
                    {
                        break;
                    }
                }

                double g = 0;
                for (int z = i + 1; z <= k; ++z)
                {
                    ThrowIfCancellationRequested();

                    RectangleWrapper <TObject> v = WrappedRectangles[z];
                    v.Rectangle.X += (z - i) * 0.0001;
                }

                // For rectangles in [i, k], compute the left force
                if (u.CenterX > x0)
                {
                    for (int m = i; m <= k; ++m)
                    {
                        double ggg = 0;
                        for (int j = 0; j < i; ++j)
                        {
                            ThrowIfCancellationRequested();

                            Vector force = Force(WrappedRectangles[j].Rectangle, WrappedRectangles[m].Rectangle);
                            ggg = Math.Max(force.X + gamma[j], ggg);
                        }

                        RectangleWrapper <TObject> v = WrappedRectangles[m];
                        double gg = v.Rectangle.Left + ggg < leftMin.Rectangle.Left ? sigma : ggg;
                        g = Math.Max(g, gg);
                    }
                }

                // Compute offset to elements in x
                // and redefine left side
                for (int m = i; m <= k; ++m)
                {
                    ThrowIfCancellationRequested();

                    gamma[m] = g;
                    RectangleWrapper <TObject> r = WrappedRectangles[m];
                    x[m] = r.Rectangle.Left + g;
                    if (r.Rectangle.Left < leftMin.Rectangle.Left)
                    {
                        leftMin = r;
                    }
                }

                // Compute the right force of rectangles in [i, k] and store the maximal one
                // delta = max(0, max{f.x(m,j)|i<=m<=k<j<n})
                double delta = 0;
                for (int m = i; m <= k; ++m)
                {
                    for (int j = k + 1; j < n; ++j)
                    {
                        ThrowIfCancellationRequested();

                        Vector force = Force(WrappedRectangles[m].Rectangle, WrappedRectangles[j].Rectangle);
                        if (force.X > delta)
                        {
                            delta = force.X;
                        }
                    }
                }
                sigma += delta;
                i      = k + 1;
            }

            double cost = 0;

            for (i = 0; i < n; ++i)
            {
                RectangleWrapper <TObject> r = WrappedRectangles[i];
                double oldPos = r.Rectangle.Left;
                double newPos = x[i];

                r.Rectangle.X = newPos;

                double diff = oldPos - newPos;
                cost += diff * diff;
            }

            return(cost);
        }
        /// <summary>
        /// Vertical improvement.
        /// </summary>
        protected double VerticalImproved()
        {
            WrappedRectangles.Sort(YComparison);
            int i = 0;
            int n = WrappedRectangles.Count;

            RectangleWrapper <TObject> topMin = WrappedRectangles[0];
            double sigma = 0;
            double y0    = topMin.CenterY;
            var    gamma = new double[WrappedRectangles.Count];
            var    y     = new double[WrappedRectangles.Count];

            while (i < n)
            {
                RectangleWrapper <TObject> u = WrappedRectangles[i];

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

                    RectangleWrapper <TObject> v = WrappedRectangles[j];
                    if (NearEqual(u.CenterY, v.CenterY))
                    {
                        u = v;
                        k = j;
                    }
                    else
                    {
                        break;
                    }
                }

                double g = 0;
                if (u.CenterY > y0)
                {
                    for (int m = i; m <= k; ++m)
                    {
                        double ggg = 0;
                        for (int j = 0; j < i; ++j)
                        {
                            ThrowIfCancellationRequested();

                            Vector f = Force2(WrappedRectangles[j].Rectangle, WrappedRectangles[m].Rectangle);
                            ggg = Math.Max(f.Y + gamma[j], ggg);
                        }

                        RectangleWrapper <TObject> v = WrappedRectangles[m];
                        double gg = v.Rectangle.Top + ggg < topMin.Rectangle.Top
                            ? sigma
                            : ggg;
                        g = Math.Max(g, gg);
                    }
                }

                for (int m = i; m <= k; ++m)
                {
                    ThrowIfCancellationRequested();

                    gamma[m] = g;
                    RectangleWrapper <TObject> r = WrappedRectangles[m];
                    y[m] = r.Rectangle.Top + g;
                    if (r.Rectangle.Top < topMin.Rectangle.Top)
                    {
                        topMin = r;
                    }
                }

                // delta = max(0, max{f.x(m,j)|i<=m<=k<j<n})
                double delta = 0;
                for (int m = i; m <= k; ++m)
                {
                    for (int j = k + 1; j < n; ++j)
                    {
                        ThrowIfCancellationRequested();

                        Vector force = Force(WrappedRectangles[m].Rectangle, WrappedRectangles[j].Rectangle);
                        if (force.Y > delta)
                        {
                            delta = force.Y;
                        }
                    }
                }
                sigma += delta;
                i      = k + 1;
            }

            double cost = 0;

            for (i = 0; i < n; ++i)
            {
                RectangleWrapper <TObject> r = WrappedRectangles[i];
                double oldPos = r.Rectangle.Top;
                double newPos = y[i];

                r.Rectangle.Y = newPos;

                double diff = oldPos - newPos;
                cost += diff * diff;
            }

            return(cost);
        }