Example #1
0
        /// <summary>
        /// Performs the Extended Wilkinson algorithm which returns an optimal labeling for numeric numbers based on the given settings
        /// </summary>
        /// <param name="availableSpace">States how much space in world units there is available for the axis</param>
        /// <param name="horizontalAxis">If set to true, the axis is orientated horizontally</param>
        /// <param name="targetDensity">Specifies how many labels should be placed per world unit</param>
        /// <param name="dataMin">The minimum of the data range</param>
        /// <param name="dataMax">The maximum of the dtaa range</param>
        /// <param name="axisMin">Gives the chosen minimum of the axis labeling</param>
        /// <param name="axisMax">Gives the chosen maximum of the axis labeling</param>
        /// <returns>An axis configuration which includes styling and the chosen labels</returns>
        public static IDisplayAxis PerformExtendedWilkinson(IAxis axis, float availableSpace, float targetDensity, out float axisMin, out float axisMax)
        {
            float bestScore = -2;

            axisMin = axis.NumericDataMin;
            axisMax = axis.NumericDataMax;

            if (axisMin == axisMax)
            {
                Debug.LogError("Cannot work on same min and max data");
                return(null);
            }

            IDisplayAxis bestOption = null;

            for (int j = 1; j < int.MaxValue; j++) // there are break statements which terminate this loop
            {
                foreach (float q in Q)             // (j,q): determines step size
                {
                    float sm = SimplicityMax(q, j);
                    if (Vector4.Dot(new Vector4(sm, 1, 1, 1), weights) < bestScore)
                    {
                        // finish the search
                        j = int.MaxValue - 1;
                        break;
                    }
                    for (int k = 2; k < int.MaxValue; k++) // try different numbers of labels
                    {
                        float dm = DensityMax(k / availableSpace, targetDensity);
                        if (Vector4.Dot(new Vector4(sm, 1, dm, 1), weights) < bestScore)
                        {
                            break;
                        }
                        float delta = (axis.NumericDataMax - axis.NumericDataMin) / (k + 1) / (j * q);
                        for (int z = Mathf.CeilToInt(Mathf.Log10(delta)); z < int.MaxValue; z++) // power of 10 multiplier for the step size
                        {
                            float lStep = q * j * Mathf.Pow(10, z);
                            float cm    = CoverageMax(axis.NumericDataMin, axis.NumericDataMax, lStep * (k - 1));
                            if (Vector4.Dot(new Vector4(sm, cm, dm, 1), weights) < bestScore)
                            {
                                break;
                            }
                            for (float start = Mathf.Floor(axis.NumericDataMax / lStep) - (k - 1); start <= Mathf.Ceil(axis.NumericDataMin / lStep); start += 1f / j) // possible start labels
                            {
                                float lmin = start * lStep;
                                float lmax = lmin + (k - 1) * lStep;
                                float s    = Simplicity(q, j, lmin, lmax, lStep);
                                float d    = Density(k / availableSpace, targetDensity);
                                float c    = Coverage(axis.NumericDataMin, axis.NumericDataMax, lmin, lmax);

                                if (Vector4.Dot(new Vector4(s, c, d, 1), weights) < bestScore)
                                {
                                    continue;
                                }

                                List <float> stepSequence = Enumerable.Range(0, k).Select(x => lmin + x * lStep).ToList();
                                //List<string> labels = stepSequence.Select(value => value.ToString("0.##")).ToList();

                                // optimize legibility
                                List <IDisplayAxis> possibilities = axis.GeneratePossibleConfigurations(minTextSize, maxTextSize, stepSequence);
                                float        legibility;
                                IDisplayAxis localBest = DisplayAxis.FindBestLegibility(possibilities, out legibility, minTextSize, targetTextSize, 0.02f, availableSpace);

                                float score = Vector4.Dot(new Vector4(s, c, d, legibility), weights);
                                if (score > bestScore)
                                {
                                    bestOption = localBest;
                                    bestScore  = score;
                                    axisMax    = lmax;
                                    axisMin    = lmin;
                                }
                            }
                        }
                    }
                }
            }
            return(bestOption);
        }