Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

OpenWPFChart: Assembling Charts from Components. Part II - Controls

, 26 Mar 2009
Chart controls composed from Chart Parts
SourceCode.zip
trunk
ChartControls
ChartControls.csproj.user
OpenWPFChart.Chart.Icon.png
OpenWPFChart.WellLogChart.Icon.png
Properties
Themes
ChartHelpers
AxisPropertiesDialog
ChartHelpers.csproj.user
ChartScaleControl
FontChooser
ItemPropertiesDialog
Properties
ChartParts
Axes
ChartParts.csproj.user
Grid
Items
Data
DataView
Elements
Visuals
NumericalRecipes
Properties
Scales
SampleDataFiles
WellLog
Samples
ControlSamples
ColumnChartControlSample
Properties
Settings.settings
CurveChartControlSample
Properties
Settings.settings
r3xyqstb.tmp_proj
WellLogControlSample
Properties
Settings.settings
DirectCompositionSamples
BasicSample
Properties
Settings.settings
TemperatureSample
Properties
Settings.settings
WellLogSample
Properties
Settings.settings
// <copyright file="ChartLogarithmicScale.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2008 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2008-12-23</date>
// <summary>OpenWPFChart library. Logarithmic ChartScale of double type and its decorations layout.</summary>
// <revision>$Id: ChartLogarithmicScale.cs 18093 2009-03-16 04:15:06Z unknown $</revision>

using System;
using System.Collections.Generic;

namespace OpenWPFChart.Parts
{
	/// <summary>
	/// Logarithmic ChartScale of the <see langword="double"/> base type and its decorations layout.
	/// <remarks>
	/// <see cref="ChartLogarithmicScale"/> requires the <see cref="ChartScale.Start"/> and <see cref="ChartScale.Stop"/>
	/// properties values are convertible to the <see langword="double"/> type.
	/// <para>This class Scale property means pixel count per logarithmic base.</para>
	/// </remarks>
	/// </summary>
	public class ChartLogarithmicScale : ChartScale
	{
		#region Constructors
		/// <summary>
		/// Initializes a new instance of the <see cref="ChartLogarithmicScale"/> class.
		/// </summary>
		/// <overloads>
		/// <summary><see cref="ChartLogarithmicScale"/> constructors.</summary>
		/// <remarks>
		/// Parametrized constructors arrange the Scale properties so that it fills itself 
		/// confortable in the screen extent propvided.
		/// </remarks>
		/// </overloads>
		public ChartLogarithmicScale() { }

		/// <summary>
		/// Initializes a new instance of the <see cref="ChartLogarithmicScale"/> class.
		/// </summary>
		/// <remarks>
		/// Arranges the Scale so that it fills itself confortable in the screen extent propvided.
		/// </remarks>
		/// <param name="start">Scale start.</param>
		/// <param name="stop">Scale stop.</param>
		/// <param name="extent">Scale visual extent in pixels.</param>
		public ChartLogarithmicScale(double start, double stop, double extent)
		{
			autoArrage(start, stop, extent);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ChartLogarithmicScale"/> class.
		/// </summary>
		/// <remarks>
		/// Arranges the Scale so that it fills itself confortable in the screen extent propvided.
		/// </remarks>
		/// <param name="start">Scale start.</param>
		/// <param name="stop">Scale stop.</param>
		/// <param name="extent">Scale visual extent in pixels.</param>
		public ChartLogarithmicScale(object start, object stop, double extent)
		{
			try
			{
				double dblStart = Convert.ToDouble(start), dblStop = Convert.ToDouble(stop);
				autoArrage(dblStart, dblStop, extent);
			}
			catch (InvalidCastException)
			{
			}
		}

		/// <summary>
		/// Arranges the Scale so that it fills itself confortable in the screen extent propvided.
		/// </summary>
		/// <param name="start">Scale start.</param>
		/// <param name="stop">Scale stop.</param>
		/// <param name="extent">Scale visual extent in pixels.</param>
		void autoArrage(double start, double stop, double extent)
		{
			if (start > 0 && stop > 0 && start != stop)
			{
				Start = start;
				Stop = stop;
				if (start > stop)
					Scale = extent / Math.Log10(start / stop);
				else
					Scale = extent / Math.Log10(stop / start);
			}
		}
		#endregion Constructors

		#region TickMask
		LogarithmicScaleTicks tickMask = LogarithmicScaleTicks.All;
		/// <summary>
		/// Gets or sets the TickMask property.
		/// </summary>
		/// <remarks>
		/// Ticks iterator returns masked ticks only.
		/// </remarks>
		/// <value></value>
		public LogarithmicScaleTicks TickMask
		{
			get { return tickMask; }
			set
			{
				if (tickMask != value)
				{
					tickMask = value;
					NotifyPropertyChanged("TickMask");
				}
			}
		}
		#endregion TickMask

		/// <inheritdoc />
		public override bool IsConsistent
		{
			get
			{
				if (!base.IsConsistent)
					return false;
				try
				{
					double start = Convert.ToDouble(Start);
					if (double.IsNaN(start) || double.IsInfinity(start))
						return false;
					double stop = Convert.ToDouble(Stop);
					if (double.IsNaN(stop) || double.IsInfinity(stop))
						return false;
					if (start > 0.0 && stop > 0.0 && start != stop)
						return true;
					return false;
				}
				catch (InvalidCastException)
				{
					return false;
				}
			}
		}

		/// <inheritdoc />
		public override double ToPixels(object value)
		{
			if (!IsConsistent)
				throw new InvalidOperationException("Object isn't properly initialized");
			double doubleValue = Convert.ToDouble(value), start = Convert.ToDouble(Start)
				, stop = Convert.ToDouble(Stop), scale = Scale;

			if (start < stop)
				return Math.Log10(doubleValue / start) * scale;
			else // (start > stop)
				return Math.Log10(start / doubleValue) * scale;
		}

		/// <inheritdoc />
		public override object FromPixels(double value)
		{
			if (!IsConsistent)
				throw new InvalidOperationException("Object isn't properly initialized");
			double start = Convert.ToDouble(Start), stop = Convert.ToDouble(Stop), scale = Scale;

			if (start < stop)
				return start * Math.Pow(10, value / scale);
			else // (start > stop)
				return start / Math.Pow(10, value / scale);
		}

		#region Ticks iterator
		/// <inheritdoc />
		public override IEnumerable<ScaleTick> Ticks()
		{
			if (!IsConsistent)
				yield break;

			double start = Convert.ToDouble(Start), stop = Convert.ToDouble(Stop);
			if (start <= 0.0 || stop <= 0.0 || start == stop)
				yield break;
			int mask = (int)TickMask;
			
			if (start < stop)
			{
				double tickPos = adjacentTick(start, true);
				if (tickPos > stop)
					yield break;
				double power;
				int tick = DecimateTick(tickPos, out power);

				while (tickPos <= stop)
				{
					if (tick == 1)
						yield return new ScaleTick(tickPos, true);
					else if (((1 << tick - 2) & mask) != 0)
						yield return new ScaleTick(tickPos, false);

					tick++;
					if (tick == 10)
					{
						tick = 1;
						power *= 10;
					}
					tickPos = tick * power;
				}
			}
			else // start > stop
			{
				double tickPos = adjacentTick(start, false);
				if (tickPos < stop)
					yield break;
				double power;
				int tick = DecimateTick(tickPos, out power);

				while (tickPos >= stop)
				{
					if (tick == 1)
						yield return new ScaleTick(tickPos, true);
					else if (((1 << tick - 2) & mask) != 0)
						yield return new ScaleTick(tickPos, false);

					tick--;
					if (tick == 0)
					{
						tick = 9;
						power /= 10;
					}
					tickPos = tick * power;
				}
			}
		}

		/// <summary>
		/// Presents tick value as a*10^n where n - any intger; a - integer, 1 &lt;= a &lt; 10.
		/// </summary>
		/// <param name="tick">input Tick value.</param>
		/// <param name="power">output value of 10^n.</param>
		/// <returns>truncated integer value of a</returns>
		private static int DecimateTick(double tick, out double power)
		{
			double log = Math.Log10(tick);
			int n = (int)log;
			power = Math.Pow(10, n);
			return (int)(tick / power);
		}

		/// <summary>
		/// Get the Tick adjacent (prev or next) to the value specified.
		/// </summary>
		/// <param name="value"></param>
		/// <param name="bNext">next or previous</param>
		/// <returns></returns>
		private static double adjacentTick(double value, bool bNext)
		{
			if (value == 1.0)
				return 1.0;

			// Present value as a*10^n where n - any intger; 1.0 <= a < 10.0
			double log = Math.Log10(value);
			int n = (int)log;
			if (log < 0.0)
				n--;
			double power = Math.Pow(10, n);
			double a = value / power;
			int tick = (int)a;
			if (tick * power == value)
				return value;
			if (bNext)
				return (tick + 1) * power;
			else
				return tick * power;
		}
		#endregion Ticks iterator
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Oleg V. Polikarpotchkin
Team Leader
Russian Federation Russian Federation
No Biography provided

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 26 Mar 2009
Article Copyright 2009 by Oleg V. Polikarpotchkin
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid