예제 #1
0
        /// <summary>
        /// Gets index of segment that should be started from zero.
        /// </summary>
        /// <param name="axisSegments">Axis scale segment collection.</param>
        /// <returns>Index axis segment or -1.</returns>
        private int GetStartScaleFromZeroSegmentIndex(AxisScaleSegmentCollection axisSegments)
        {
            if (this.StartFromZero == StartFromZero.Auto ||
                this.StartFromZero == StartFromZero.Yes)
            {
                int index = 0;
                foreach (AxisScaleSegment axisScaleSegment in axisSegments)
                {
                    // Check if zero value is already part of the scale
                    if (axisScaleSegment.ScaleMinimum < 0.0 && axisScaleSegment.ScaleMaximum > 0.0)
                    {
                        return(-1);
                    }

                    // As soon as we get first segment with positive minimum value or
                    // we reached last segment adjust scale to start from zero.
                    if (axisScaleSegment.ScaleMinimum > 0.0 ||
                        index == (axisSegments.Count - 1))
                    {
                        // Check if setting minimum scale to zero will make the
                        // data points in the segment hard to read. This may hapen
                        // when the distance from zero to current minimum is
                        // significantly larger than current scale size.
                        if (this.StartFromZero == StartFromZero.Auto &&
                            axisScaleSegment.ScaleMinimum > 2.0 * (axisScaleSegment.ScaleMaximum - axisScaleSegment.ScaleMinimum))
                        {
                            return(-1);
                        }

                        return(index);
                    }

                    // Increase segment index
                    ++index;
                }
            }
            return(-1);
        }
예제 #2
0
        /// <summary>
        /// Fill collection of axis scale segments.
        /// </summary>
        /// <param name="axisSegments">Collection of axis segments.</param>
        private void FillAxisSegmentCollection(AxisScaleSegmentCollection axisSegments)
        {
            // Clear axis segments collection
            axisSegments.Clear();

            // Get statistics for the series attached to the axis
            double minYValue   = 0.0;
            double maxYValue   = 0.0;
            double segmentSize = 0.0;

            double[] segmentMaxValue    = null;
            double[] segmentMinValue    = null;
            int[]    segmentPointNumber = GetSeriesDataStatistics(
                this._totalNumberOfSegments,
                out minYValue,
                out maxYValue,
                out segmentSize,
                out segmentMaxValue,
                out segmentMinValue);
            if (segmentPointNumber == null)
            {
                return;
            }

            // Calculate scale maximum and minimum
            double minimum = minYValue;
            double maximum = maxYValue;

            this.axis.EstimateNumberAxis(
                ref minimum,
                ref maximum,
                this.axis.IsStartedFromZero,
                this.axis.prefferedNumberofIntervals,
                true,
                true);

            // Make sure max/min Y values are not the same
            if (maxYValue == minYValue)
            {
                return;
            }

            // Calculate the percentage of the scale range covered by the data range.
            double dataRangePercent = (maxYValue - minYValue) / ((maximum - minimum) / 100.0);

            // Get sequences of empty segments
            ArrayList emptySequences = new ArrayList();
            bool      doneFlag       = false;

            while (!doneFlag)
            {
                doneFlag = true;

                // Get longest sequence of segments with no points
                int startSegment     = 0;
                int numberOfSegments = 0;
                this.GetLargestSequenseOfSegmentsWithNoPoints(
                    segmentPointNumber,
                    out startSegment,
                    out numberOfSegments);

                // Adjust minimum empty segments  number depending on current segments
                int minEmptySegments = (int)(this._minimumNumberOfEmptySegments * (100.0 / dataRangePercent));
                if (axisSegments.Count > 0 && numberOfSegments > 0)
                {
                    // Find the segment which contain newly found empty segments sequence
                    foreach (AxisScaleSegment axisScaleSegment in axisSegments)
                    {
                        if (startSegment > 0 && (startSegment + numberOfSegments) <= segmentMaxValue.Length - 1)
                        {
                            if (segmentMaxValue[startSegment - 1] >= axisScaleSegment.ScaleMinimum &&
                                segmentMinValue[startSegment + numberOfSegments] <= axisScaleSegment.ScaleMaximum)
                            {
                                // Get percentage of segment scale that is empty and suggested for collapsing
                                double segmentScaleRange = axisScaleSegment.ScaleMaximum - axisScaleSegment.ScaleMinimum;
                                double emptySpaceRange   = segmentMinValue[startSegment + numberOfSegments] - segmentMaxValue[startSegment - 1];
                                double emptySpacePercent = emptySpaceRange / (segmentScaleRange / 100.0);
                                emptySpacePercent = emptySpacePercent / 100 * axisScaleSegment.Size;

                                if (emptySpacePercent > minEmptySegments &&
                                    numberOfSegments > this._minSegmentSize)
                                {
                                    minEmptySegments = numberOfSegments;
                                }
                            }
                        }
                    }
                }

                // Check if found sequence is long enough
                if (numberOfSegments >= minEmptySegments)
                {
                    doneFlag = false;

                    // Store start segment and number of segments in the list
                    emptySequences.Add(startSegment);
                    emptySequences.Add(numberOfSegments);

                    // Check if there are any emty segments sequence found
                    axisSegments.Clear();
                    if (emptySequences.Count > 0)
                    {
                        double segmentFrom = double.NaN;
                        double segmentTo   = double.NaN;

                        // Based on the segments that need to be excluded create axis segments that
                        // will present on the axis scale.
                        int numberOfPoints = 0;
                        for (int index = 0; index < segmentPointNumber.Length; index++)
                        {
                            // Check if current segment is excluded
                            bool excludedSegment = this.IsExcludedSegment(emptySequences, index);

                            // If not excluded segment - update from/to range if they were set
                            if (!excludedSegment &&
                                !double.IsNaN(segmentMinValue[index]) &&
                                !double.IsNaN(segmentMaxValue[index]))
                            {
                                // Calculate total number of points
                                numberOfPoints += segmentPointNumber[index];

                                // Set From/To of the visible segment
                                if (double.IsNaN(segmentFrom))
                                {
                                    segmentFrom = segmentMinValue[index];
                                    segmentTo   = segmentMaxValue[index];
                                }
                                else
                                {
                                    segmentTo = segmentMaxValue[index];
                                }
                            }

                            // If excluded or last segment - add current visible segment range
                            if (!double.IsNaN(segmentFrom) &&
                                (excludedSegment || index == (segmentPointNumber.Length - 1)))
                            {
                                // Make sure To and From do not match
                                if (segmentTo == segmentFrom)
                                {
                                    segmentFrom -= segmentSize;
                                    segmentTo   += segmentSize;
                                }

                                // Add axis scale segment
                                AxisScaleSegment axisScaleSegment = new AxisScaleSegment();
                                axisScaleSegment.ScaleMaximum = segmentTo;
                                axisScaleSegment.ScaleMinimum = segmentFrom;
                                axisScaleSegment.Tag          = numberOfPoints;
                                axisSegments.Add(axisScaleSegment);

                                // Reset segment range
                                segmentFrom    = double.NaN;
                                segmentTo      = double.NaN;
                                numberOfPoints = 0;
                            }
                        }
                    }

                    // Calculate the position of each segment
                    this.SetAxisSegmentPosition(axisSegments);
                }

                // Make sure we do not exceed specified number of breaks
                if ((axisSegments.Count - 1) >= this._maximumNumberOfBreaks)
                {
                    doneFlag = true;
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Sets position of all scale segments in the axis.
        /// </summary>
        /// <param name="axisSegments">Collection of axis scale segments.</param>
        private void SetAxisSegmentPosition(AxisScaleSegmentCollection axisSegments)
        {
            // Calculate total number of points
            int totalPointNumber = 0;

            foreach (AxisScaleSegment axisScaleSegment in axisSegments)
            {
                if (axisScaleSegment.Tag is int)
                {
                    totalPointNumber += (int)axisScaleSegment.Tag;
                }
            }

            // Calculate segment minimum size
            double minSize = Math.Min(this._minSegmentSize, Math.Floor(100.0 / axisSegments.Count));

            // Set segment position
            double currentPosition = 0.0;

            for (int index = 0; index < axisSegments.Count; index++)
            {
                axisSegments[index].Position = (currentPosition > 100.0) ? 100.0 : currentPosition;
                axisSegments[index].Size     = Math.Round(((int)axisSegments[index].Tag) / (totalPointNumber / 100.0), 5);
                if (axisSegments[index].Size < minSize)
                {
                    axisSegments[index].Size = minSize;
                }

                // Set spacing for all segments except the last one
                if (index < (axisSegments.Count - 1))
                {
                    axisSegments[index].Spacing = this._segmentSpacing;
                }

                // Advance current position
                currentPosition += axisSegments[index].Size;
            }

            // Make sure we do not exceed the 100% axis length
            double totalHeight = 0.0;

            do
            {
                // Calculate total height
                totalHeight = 0.0;
                double maxSize      = double.MinValue;
                int    maxSizeIndex = -1;
                for (int index = 0; index < axisSegments.Count; index++)
                {
                    totalHeight += axisSegments[index].Size;
                    if (axisSegments[index].Size > maxSize)
                    {
                        maxSize      = axisSegments[index].Size;
                        maxSizeIndex = index;
                    }
                }

                // If height is too large find largest segment
                if (totalHeight > 100.0)
                {
                    // Adjust segment size
                    axisSegments[maxSizeIndex].Size -= totalHeight - 100.0;
                    if (axisSegments[maxSizeIndex].Size < minSize)
                    {
                        axisSegments[maxSizeIndex].Size = minSize;
                    }

                    // Adjust position of the next segment
                    double curentPosition = axisSegments[maxSizeIndex].Position + axisSegments[maxSizeIndex].Size;
                    for (int index = maxSizeIndex + 1; index < axisSegments.Count; index++)
                    {
                        axisSegments[index].Position = curentPosition;
                        curentPosition += axisSegments[index].Size;
                    }
                }
            } while(totalHeight > 100.0);
        }
예제 #4
0
        /// <summary>
        /// Get collection of axis segments to present scale breaks.
        /// </summary>
        /// <param name="axisSegments">Collection of axis scale segments.</param>
        internal void GetAxisSegmentForScaleBreaks(AxisScaleSegmentCollection axisSegments)
        {
            // Clear segment collection
            axisSegments.Clear();

            // Check if scale breaks are enabled
            if (this.IsEnabled())
            {
                // Fill collection of segments
                this.FillAxisSegmentCollection(axisSegments);

                // Check if more than 1 segments were defined
                if (axisSegments.Count >= 1)
                {
                    // Get index of segment which scale should start from zero
                    int startFromZeroSegmentIndex = this.GetStartScaleFromZeroSegmentIndex(axisSegments);

                    // Calculate segment interaval and round the scale
                    int index = 0;
                    foreach (AxisScaleSegment axisScaleSegment in axisSegments)
                    {
                        // Check if segment scale should start from zero
                        bool startFromZero = (index == startFromZeroSegmentIndex) ? true : false;

                        // Calculate interval and round scale
                        double minimum = axisScaleSegment.ScaleMinimum;
                        double maximum = axisScaleSegment.ScaleMaximum;
                        axisScaleSegment.Interval = this.axis.EstimateNumberAxis(
                            ref minimum, ref maximum, startFromZero, this.axis.prefferedNumberofIntervals, true, true);
                        axisScaleSegment.ScaleMinimum = minimum;
                        axisScaleSegment.ScaleMaximum = maximum;

                        // Make sure new scale break value range do not exceed axis current scale
                        if (axisScaleSegment.ScaleMinimum < this.axis.Minimum)
                        {
                            axisScaleSegment.ScaleMinimum = this.axis.Minimum;
                        }
                        if (axisScaleSegment.ScaleMaximum > this.axis.Maximum)
                        {
                            axisScaleSegment.ScaleMaximum = this.axis.Maximum;
                        }

                        // Increase segment index
                        ++index;
                    }

                    // Defined axis scale segments cannot overlap.
                    // Check for overlapping and join segments or readjust min/max.
                    bool             adjustPosition = false;
                    AxisScaleSegment prevSegment    = axisSegments[0];
                    for (int segmentIndex = 1; segmentIndex < axisSegments.Count; segmentIndex++)
                    {
                        AxisScaleSegment currentSegment = axisSegments[segmentIndex];
                        if (currentSegment.ScaleMinimum <= prevSegment.ScaleMaximum)
                        {
                            if (currentSegment.ScaleMaximum > prevSegment.ScaleMaximum)
                            {
                                // If segments are partially overlapping make sure the previous
                                // segment scale is extended
                                prevSegment.ScaleMaximum = currentSegment.ScaleMaximum;
                            }

                            // Remove the overlapped segment
                            adjustPosition = true;
                            axisSegments.RemoveAt(segmentIndex);
                            --segmentIndex;
                        }
                        else
                        {
                            prevSegment = currentSegment;
                        }
                    }

                    // Calculate the position of each segment
                    if (adjustPosition)
                    {
                        this.SetAxisSegmentPosition(axisSegments);
                    }
                }
            }
        }