Esempio n. 1
0
        /// <summary>
        /// Select a reasonable base 10 logarithmic axis scale given a range of data values.
        /// </summary>
        /// <remarks>
        /// This method only applies to <see cref="AxisType.Log"/> type axes, and it
        /// is called by the general <see cref="PickScale"/> method.  The scale range is chosen
        /// based always on powers of 10 (full log cycles).  This
        /// method honors the <see cref="Scale.MinAuto"/>, <see cref="Scale.MaxAuto"/>,
        /// and <see cref="Scale.MajorStepAuto"/> autorange settings.
        /// In the event that any of the autorange settings are false, the
        /// corresponding <see cref="Scale.Min"/>, <see cref="Scale.Max"/>, or <see cref="Scale.MajorStep"/>
        /// setting is explicitly honored, and the remaining autorange settings (if any) will
        /// be calculated to accomodate the non-autoranged values.  For log axes, the MinorStep
        /// value is not used.
        /// <para>On Exit:</para>
        /// <para><see cref="Scale.Min"/> is set to scale minimum (if <see cref="Scale.MinAuto"/> = true)</para>
        /// <para><see cref="Scale.Max"/> is set to scale maximum (if <see cref="Scale.MaxAuto"/> = true)</para>
        /// <para><see cref="Scale.MajorStep"/> is set to scale step size (if <see cref="Scale.MajorStepAuto"/> = true)</para>
        /// <para><see cref="Scale.Mag"/> is set to a magnitude multiplier according to the data</para>
        /// <para><see cref="Scale.Format"/> is set to the display format for the values (this controls the
        /// number of decimal places, whether there are thousands separators, currency types, etc.)</para>
        /// </remarks>
        /// <param name="pane">A reference to the <see cref="GraphPane"/> object
        /// associated with this <see cref="Axis"/></param>
        /// <param name="g">
        /// A graphic device object to be drawn into.  This is normally e.Graphics from the
        /// PaintEventArgs argument to the Paint() method.
        /// </param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
        /// font sizes, etc. according to the actual size of the graph.
        /// </param>
        /// <seealso cref="PickScale"/>
        /// <seealso cref="AxisType.Log"/>
        public override void PickScale( GraphPane pane, IGraphics g, float scaleFactor )
        {
            double minVal = _rangeMin;
            double maxVal = _rangeMax;

            // Make sure that minVal and maxVal are legitimate values
            if (Double.IsInfinity(minVal) || Double.IsNaN(minVal) || minVal == Double.MaxValue)
                minVal = 0.0;
            if (Double.IsInfinity(maxVal) || Double.IsNaN(maxVal) || maxVal == Double.MaxValue)
                maxVal = 0.0;

            if(minVal > maxVal)
            {
                double t = maxVal;
                maxVal = minVal;
                minVal = t;
            }

            // Check for bad data range
            if (minVal <= 0.0 && maxVal <= 0.0)
            {
                minVal = 1.0;
                maxVal = 10.0;
            }
            else if (minVal <= 0.0)
            {
                minVal = maxVal / 10.0;
            }

            double range = maxVal - minVal;

            // For autoranged values, assign the value.  If appropriate, adjust the value by the
            // "Grace" value.
            if(_minAuto)
            {
                if(_minGrace < 0)
                {
                    _minGrace = 0;
                }
                double graceVal = CalcMinValue(minVal, maxVal, _minGrace);
                double nextProperPowerOf10 = Math.Pow(10.0, Math.Floor(Math.Log10(minVal)));
                _min = graceVal < nextProperPowerOf10 ? nextProperPowerOf10 : graceVal; // don't use grace val if there is a power of 10 between the data start and the garce value
            }

            if(_maxAuto)
            {
                if(_maxGrace < 0)
                {
                    _maxGrace = 0;
                }
                double graceVal = CalcMaxValue(minVal, maxVal, _maxGrace);
                double nextProperPowerOf10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(maxVal)));
                _max = graceVal > nextProperPowerOf10 ? nextProperPowerOf10 : graceVal;
            }

            // if min == max and we are auto scaling, make the scale go from -5% to +5%
            if (_max == _min && _maxAuto && _minAuto)
            {
                if (Math.Abs(_max) > 1e-100)
                {
                    _max *= (_min < 0 ? 0.95 : 1.05);
                    _min *= (_min < 0 ? 1.05 : 0.95);
                }
                else
                {
                    _max = 1.0;
                    _min = -1.0;
                }
            }

            _mag = 0;		// Never use a magnitude shift for log scales
            //this.numDec = 0;		// The number of decimal places to display is not used

            // Test for trivial condition of range = 0 and pick a suitable default
            if ( _max - _min < SmallestValue )
            {
                if ( _maxAuto )
                    _max = _max * 2.0;
                if ( _minAuto )
                    _min = _min / 2.0;
            }

            if(UsingLinearlySpacedTickMarks) // this method gets called again after the initial setup - so _linScale may already be set
            {
                //_linScale.PickScale(pane, g, scaleFactor);
                _min = _linScale._min;
                _max = _linScale._max;
                return;
            }

            int nTicks = CalcNumTics(); // get the number of ticks
            if (UseMostSuitableTickMarkSpacing && nTicks < MinimumNumberOfMajorTicks) // then we shall use a linear scale instead
            {
                // Calculate the new step size
                double majorStep = _majorStep;
                if (_majorStepAuto)
                {
                    double targetSteps = (_ownerAxis is XAxis || _ownerAxis is X2Axis) ? Default.TargetXSteps : Default.TargetYSteps;
                    // Calculate the step size based on target steps
                    majorStep = CalcStepSize(_max - _min, targetSteps);
                    if (_isPreventLabelOverlap)
                    {
                        // Calculate the maximum number of labels
                        double maxLabels = (double)this.CalcMaxLabels(g, pane, scaleFactor); // Will this work?
                        if (maxLabels < (_max - _min) / _majorStep)
                        {
                            majorStep = CalcBoundedStepSize(_max - _min, maxLabels);
                        }
                    }
                }

                LinearScale altLinScale = new LinearScale(this, _ownerAxis)
                                              {
                                                          _rangeMin = this._rangeMin,
                                                          _rangeMax = this._rangeMax,
                                                          MajorStep = majorStep,
                                                          _min = this._min,
                                                          _max = this._max
                                                };

                // Special case.  If range is zero, then we have already adjusted our _min and max to 95% to 105%.
                // I do not want the linear scale to adda a grace on to this as well.
                if(range == 0)
                {
                    altLinScale._minGrace = 0;
                    altLinScale._maxGrace = 0;
                }
                _linScale = altLinScale;
                return;
            }

            // Majorstep is always 1 for log scales
            if (_majorStepAuto)
                _majorStep = 1.0;
        }
Esempio n. 2
0
        /// <summary>
        /// Select a reasonable base 10 logarithmic axis scale given a range of data values.
        /// </summary>
        /// <remarks>
        /// This method only applies to <see cref="AxisType.Log"/> type axes, and it
        /// is called by the general <see cref="PickScale"/> method.  The scale range is chosen
        /// based always on powers of 10 (full log cycles).  This
        /// method honors the <see cref="Scale.MinAuto"/>, <see cref="Scale.MaxAuto"/>,
        /// and <see cref="Scale.MajorStepAuto"/> autorange settings.
        /// In the event that any of the autorange settings are false, the
        /// corresponding <see cref="Scale.Min"/>, <see cref="Scale.Max"/>, or <see cref="Scale.MajorStep"/>
        /// setting is explicitly honored, and the remaining autorange settings (if any) will
        /// be calculated to accomodate the non-autoranged values.  For log axes, the MinorStep
        /// value is not used.
        /// <para>On Exit:</para>
        /// <para><see cref="Scale.Min"/> is set to scale minimum (if <see cref="Scale.MinAuto"/> = true)</para>
        /// <para><see cref="Scale.Max"/> is set to scale maximum (if <see cref="Scale.MaxAuto"/> = true)</para>
        /// <para><see cref="Scale.MajorStep"/> is set to scale step size (if <see cref="Scale.MajorStepAuto"/> = true)</para>
        /// <para><see cref="Scale.Mag"/> is set to a magnitude multiplier according to the data</para>
        /// <para><see cref="Scale.Format"/> is set to the display format for the values (this controls the
        /// number of decimal places, whether there are thousands separators, currency types, etc.)</para>
        /// </remarks>
        /// <param name="pane">A reference to the <see cref="GraphPane"/> object
        /// associated with this <see cref="Axis"/></param>
        /// <param name="g">
        /// A graphic device object to be drawn into.  This is normally e.Graphics from the
        /// PaintEventArgs argument to the Paint() method.
        /// </param>
        /// <param name="scaleFactor">
        /// The scaling factor to be used for rendering objects.  This is calculated and
        /// passed down by the parent <see cref="GraphPane"/> object using the
        /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
        /// font sizes, etc. according to the actual size of the graph.
        /// </param>
        /// <seealso cref="PickScale"/>
        /// <seealso cref="AxisType.Log"/>
        override public void PickScale(GraphPane pane, IGraphics g, float scaleFactor)
        {
            double minVal = _rangeMin;
            double maxVal = _rangeMax;

            // Make sure that minVal and maxVal are legitimate values
            if (Double.IsInfinity(minVal) || Double.IsNaN(minVal) || minVal == Double.MaxValue)
            {
                minVal = 0.0;
            }
            if (Double.IsInfinity(maxVal) || Double.IsNaN(maxVal) || maxVal == Double.MaxValue)
            {
                maxVal = 0.0;
            }

            if (minVal > maxVal)
            {
                double t = maxVal;
                maxVal = minVal;
                minVal = t;
            }

            // Check for bad data range
            if (minVal <= 0.0 && maxVal <= 0.0)
            {
                minVal = 1.0;
                maxVal = 10.0;
            }
            else if (minVal <= 0.0)
            {
                minVal = maxVal / 10.0;
            }

            double range = maxVal - minVal;

            // For autoranged values, assign the value.  If appropriate, adjust the value by the
            // "Grace" value.
            if (_minAuto)
            {
                if (_minGrace < 0)
                {
                    _minGrace = 0;
                }
                double graceVal            = CalcMinValue(minVal, maxVal, _minGrace);
                double nextProperPowerOf10 = Math.Pow(10.0, Math.Floor(Math.Log10(minVal)));
                _min = graceVal < nextProperPowerOf10 ? nextProperPowerOf10 : graceVal; // don't use grace val if there is a power of 10 between the data start and the garce value
            }

            if (_maxAuto)
            {
                if (_maxGrace < 0)
                {
                    _maxGrace = 0;
                }
                double graceVal            = CalcMaxValue(minVal, maxVal, _maxGrace);
                double nextProperPowerOf10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(maxVal)));
                _max = graceVal > nextProperPowerOf10 ? nextProperPowerOf10 : graceVal;
            }

            // if min == max and we are auto scaling, make the scale go from -5% to +5%
            if (_max == _min && _maxAuto && _minAuto)
            {
                if (Math.Abs(_max) > 1e-100)
                {
                    _max *= (_min < 0 ? 0.95 : 1.05);
                    _min *= (_min < 0 ? 1.05 : 0.95);
                }
                else
                {
                    _max = 1.0;
                    _min = -1.0;
                }
            }

            _mag = 0;                           // Never use a magnitude shift for log scales
            //this.numDec = 0;		// The number of decimal places to display is not used

            // Test for trivial condition of range = 0 and pick a suitable default
            if (_max - _min < 1.0e-20)
            {
                if (_maxAuto)
                {
                    _max = _max * 2.0;
                }
                if (_minAuto)
                {
                    _min = _min / 2.0;
                }
            }

            if (UsingLinearlySpacedTickMarks) // this method gets called again after the initial setup - so _linScale may already be set
            {
                //_linScale.PickScale(pane, g, scaleFactor);
                _min = _linScale._min;
                _max = _linScale._max;
                return;
            }

            int nTicks = CalcNumTics();                                               // get the number of ticks

            if (UseMostSuitableTickMarkSpacing && nTicks < MinimumNumberOfMajorTicks) // then we shall use a linear scale instead
            {
                // Calculate the new step size
                double majorStep = _majorStep;
                if (_majorStepAuto)
                {
                    double targetSteps = (_ownerAxis is XAxis || _ownerAxis is X2Axis) ? Default.TargetXSteps : Default.TargetYSteps;
                    // Calculate the step size based on target steps
                    majorStep = CalcStepSize(_max - _min, targetSteps);
                    if (_isPreventLabelOverlap)
                    {
                        // Calculate the maximum number of labels
                        double maxLabels = (double)this.CalcMaxLabels(g, pane, scaleFactor); // Will this work?
                        if (maxLabels < (_max - _min) / _majorStep)
                        {
                            majorStep = CalcBoundedStepSize(_max - _min, maxLabels);
                        }
                    }
                }

                LinearScale altLinScale = new LinearScale(this, _ownerAxis)
                {
                    _rangeMin = this._rangeMin,
                    _rangeMax = this._rangeMax,
                    MajorStep = majorStep,
                    _min      = this._min,
                    _max      = this._max
                };

                // Special case.  If range is zero, then we have already adjusted our _min and max to 95% to 105%.
                // I do not want the linear scale to adda a grace on to this as well.
                if (range == 0)
                {
                    altLinScale._minGrace = 0;
                    altLinScale._maxGrace = 0;
                }
                _linScale = altLinScale;
                return;
            }

            // Majorstep is always 1 for log scales
            if (_majorStepAuto)
            {
                _majorStep = 1.0;
            }
        }