// Copyright (c) Microsoft Corporation. All Rights Reserved.
// Licensed under the MIT License.
using System;
using System.Windows;
namespace InteractiveDataDisplay.WPF {
///
/// Performs transformations between data values and plot coordinates.
///
public abstract class DataTransform : DependencyObject
{
/// Gets range of valid data values. method returns NaN for
/// values outside this range.
///
public Range Domain { get; private set; }
///
/// Initializes a new instance of class.
///
/// A range of valid data.
protected DataTransform(Range domain)
{
Domain = domain;
}
///
/// Converts value from data to plot coordinates.
///
/// A value in data coordinates.
/// Value converted to plot coordinates or NaN if
/// falls outside of .
public abstract double DataToPlot(double dataValue);
///
/// Converts value from plot coordinates to data.
///
/// A value in plot coordinates.
/// Value converted to data coordinates or NaN if no value in data coordinates
/// matches .
public abstract double PlotToData(double plotValue);
/// Identity transformation
public static readonly DataTransform Identity = new IdentityDataTransform();
}
///
/// Provides identity transformation between data and plot coordinates.
///
public class IdentityDataTransform : DataTransform
{
///
/// Initializes a new instance of class.
///
public IdentityDataTransform()
: base(new Range(double.MinValue, double.MaxValue))
{
}
///
/// Returns a value in data coordinates without convertion.
///
/// A value in data coordinates.
///
public override double DataToPlot(double dataValue)
{
return dataValue;
}
///
/// Returns a value in plot coordinates without convertion.
///
/// A value in plot coordinates.
///
public override double PlotToData(double plotValue)
{
return plotValue;
}
}
///
/// Represents a mercator transform, used in maps.
/// Transforms y coordinates.
///
public sealed class MercatorTransform : DataTransform
{
///
/// Initializes a new instance of the class.
///
public MercatorTransform()
: base(new Range(-85, 85))
{
CalcScale(maxLatitude);
}
///
/// Initializes a new instance of the class.
///
/// The maximal latitude.
public MercatorTransform(double maxLatitude)
: base(new Range(-maxLatitude, maxLatitude))
{
this.maxLatitude = maxLatitude;
CalcScale(maxLatitude);
}
private void CalcScale(double inputMaxLatitude)
{
double maxLatDeg = inputMaxLatitude;
double maxLatRad = maxLatDeg * Math.PI / 180;
scale = maxLatDeg / Math.Log(Math.Tan(maxLatRad / 2 + Math.PI / 4));
}
private double scale;
///
/// Gets the scale.
///
/// The scale.
public double Scale
{
get { return scale; }
}
private double maxLatitude = 85;
///
/// Gets the maximal latitude.
///
/// The max latitude.
public double MaxLatitude
{
get { return maxLatitude; }
}
///
/// Converts value from mercator to plot coordinates.
///
/// A value in mercator coordinates.
/// Value converted to plot coordinates.
public override double DataToPlot(double dataValue)
{
if (-maxLatitude <= dataValue && dataValue <= maxLatitude)
{
dataValue = scale * Math.Log(Math.Tan(Math.PI * (dataValue + 90) / 360));
}
return dataValue;
}
///
/// Converts value from plot to mercator coordinates.
///
/// A value in plot coordinates.
/// Value converted to mercator coordinates.
public override double PlotToData(double plotValue)
{
if (-maxLatitude <= plotValue && plotValue <= maxLatitude)
{
double e = Math.Exp(plotValue / scale);
plotValue = 360 * Math.Atan(e) / Math.PI - 90;
}
return plotValue;
}
}
///
/// Provides linear transform u = * d + from data value d to plot coordinate u.
///
public sealed class LinearDataTransform : DataTransform
{
///
/// Gets or sets the scale factor.
///
public double Scale
{
get { return (double)GetValue(ScaleProperty); }
set { SetValue(ScaleProperty, value); }
}
///
/// Identifies the dependency property.
///
public static readonly DependencyProperty ScaleProperty =
DependencyProperty.Register("Scale", typeof(double), typeof(LinearDataTransform), new PropertyMetadata(1.0));
///
/// Gets or sets the distance to translate an value.
///
public double Offset
{
get { return (double)GetValue(OffsetProperty); }
set { SetValue(OffsetProperty, value); }
}
///
/// Identifies the dependency property.
///
public static readonly DependencyProperty OffsetProperty =
DependencyProperty.Register("Offset", typeof(double), typeof(LinearDataTransform), new PropertyMetadata(0.0));
///
/// Initializes a new instance of the class.
///
public LinearDataTransform()
: base(new Range(double.MinValue, double.MaxValue))
{
}
///
/// Transforms a value according to defined and .
///
/// A value in data coordinates.
/// Transformed value.
public override double DataToPlot(double dataValue)
{
return dataValue * Scale + Offset;
}
///
/// Returns a value in data coordinates from its transformed value.
///
/// Transformed value.
/// Original value or NaN if is 0.
public override double PlotToData(double plotValue)
{
if (Scale != 0)
{
return (plotValue - Offset) / Scale;
}
else
return double.NaN;
}
}
}