using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Runtime.Serialization;
using System.Xml;
using CategoryTheory;
using BaseTypes;
using DiagramUI.Labels;
using DiagramUI;
using DiagramUI.Interfaces;
using DataPerformer.Interfaces;
namespace DataPerformer
{
/// <summary>
/// Base class of all series
/// </summary>
public class SeriesBase : CategoryObject, ISerializable, IArgumentSelection,
IStructuredSelection, IStructuredSelectionCollection, IMeasure, IMeasurements, IAliasVector
{
#region Fields
protected static readonly Double a = 0;
private readonly string[] var = { "x" };
protected readonly double eps = 1e-9;
static public readonly string[] HasEqualStepString = new string[] {"This series has equal steps",
"This series has no equal steps"};
protected List<double[]> points = new List<double[]>();
protected string x = "";
protected string y = "";
protected double[] parameter = new double[2];
private object obj;
protected double step = 0;
protected int[] pointStart = new int[2];
protected int[] pointFinish = new int[2];
protected byte[] comments;
private object type = new object[] { a, a };
protected object[] meaX = new object[2];
protected object[] meaY = new object[2];
protected Func<object>[] measureParameter = new Func<object>[2];
private IMeasure measureY;
private IStructuredSelection[] selections;
protected IMeasure function;
protected IMeasure[] meas = new IMeasure[6];
private List<string> vectorNames = new List<string>();
static private readonly string[] vNames = new string[] {"Ordinates"};
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public SeriesBase()
{
foreach (string vn in vNames)
{
vectorNames.Add(vn);
}
selections = new IStructuredSelection[] { new XSelection(this), this };
initialize();
}
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
protected SeriesBase(SerializationInfo info, StreamingContext context)
{
foreach (string vn in vNames)
{
vectorNames.Add(vn);
}
try
{
points = info.GetValue("Points", typeof(List<double[]>)) as List<double[]>;
}
catch (Exception)
{
ArrayList p = info.GetValue("Points", typeof(ArrayList)) as ArrayList;
for (int i = 0; i < p.Count; i++)
{
double[] d = p[i] as double[];
points.Add(d);
}
}
}
#endregion
#region ISerializable Members
/// <summary>
/// ISerializable interface implementation
/// </summary>
/// <param name="info">Serialization info</param>
/// <param name="context">Streaming context</param>
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Points", points);
if (comments != null)
{
info.AddValue("Comments", comments);
}
}
#endregion
#region IMeasurements Members
IMeasure IMeasurements.this[int n]
{
get
{
if (n < meas.Length)
{
return meas[n];
}
return function;
}
}
public void UpdateMeasurements()
{
}
public string SourceName
{
get
{
IObjectLabel l = obj as IObjectLabel;
return l.Name;
}
}
public bool IsUpdated
{
get
{
return true;
}
set
{
}
}
int IMeasurements.Count
{
get
{
return (function == null) ? meas.Length : meas.Length + 1;
}
}
#endregion
#region IMeasure Members
public Func<object> Parameter
{
get
{
return measureParameter[0];
}
}
public Func<object> Derivation
{
get
{
return null;
}
}
public string Name
{
get
{
return "X";
}
}
public double Factor
{
get
{
return 1;
}
}
public object Type
{
get
{
InitialzeMeasurements();
return type;
}
}
#endregion
#region Specific Members
/// <summary>
/// Adds series
/// </summary>
/// <param name="series">Series to add</param>
public virtual void Add(SeriesBase series)
{
points.AddRange(series.points);
step = 0;
checkEqualStep();
}
/// <summary>
/// Copies from another series
/// </summary>
/// <param name="s">Pattern series</param>
/* public void CopyFrom(SeriesBase s)
{
points.Clear();
for (int i = 0; i < s.Count; i++)
{
AddXY(s[i, 0], s[i, 1]);
}
step = 0;
checkEqualStep();
}*/
public List<double[]> Points
{
get { return points; }
}
public string HasEqualSteps
{
get
{
if (step == 0)
{
return PureDesktop.GetResourceString(HasEqualStepString[1]);
}
return PureDesktop.GetResourceString(HasEqualStepString[0]);
}
}
/// <summary>
/// Creates correspond xml
/// </summary>
/// <param name="doc">document to create element</param>
/// <returns>The created element</returns>
public XmlElement CreateXml(XmlDocument doc)
{
XmlElement el = doc.CreateElement("Plot");
XmlAttribute nx = doc.CreateAttribute("X");
nx.Value = X;
el.Attributes.Append(nx);
XmlAttribute ny = doc.CreateAttribute("Y");
ny.Value = Y;
el.Attributes.Append(ny);
foreach (double[] p in points)
{
XmlElement ep = doc.CreateElement("PlotPoint");
XmlAttribute ax = doc.CreateAttribute("PlotX");
ax.Value = "" + p[0];
ep.Attributes.Append(ax);
XmlAttribute ay = doc.CreateAttribute("PlotY");
ay.Value = "" + p[1];
ep.Attributes.Append(ay);
el.AppendChild(ep);
}
return el;
}
/// <summary>
/// Copies from another series
/// </summary>
/// <param name="s">Pattern series</param>
public void CopyFrom(SeriesBase s)
{
points.Clear();
for (int i = 0; i < s.Count; i++)
{
AddXY(s[i, 0], s[i, 1]);
}
step = 0;
checkEqualStep();
}
/// <summary>
/// Adds point
/// </summary>
/// <param name="x">x - coordinate</param>
/// <param name="y">y - coordinate</param>
public void AddXY(double x, double y)
{
if (Double.IsNaN(x) | Double.IsNaN(y) | Double.IsInfinity(x) | Double.IsInfinity(y))
{
throw new Exception("Infinity");
}
points.Add(new double[] { x, y });
}
/// <summary>
/// Access to i - th point (j = 0 access to x - coordinate, j = 1 access to y coordinate)
/// </summary>
public double this[int i, int j]
{
get
{
double[] x = points[i] as double[];
return x[j];
}
}
/// <summary>
/// Clears itself
/// </summary>
public virtual void Clear()
{
points.Clear();
}
/// <summary>
/// Count of points
/// </summary>
public int Count
{
get
{
return points.Count;
}
}
/// <summary>
/// Size of this series
/// </summary>
public double[,] Size
{
get
{
double[,] size = new double[2, 2];
for (int i = 0; i < points.Count; i++)
{
double[] x = (double[])points[i];
if (i == 0)
{
size[0, 0] = x[0];
size[0, 1] = x[1];
size[1, 0] = x[0];
size[1, 1] = x[1];
continue;
}
for (int j = 0; j < 2; j++)
{
if (x[j] < size[0, j])
{
size[0, j] = x[j];
}
if (x[j] > size[1, j])
{
size[1, j] = x[j];
}
}
}
return size;
}
}
#region IStructuredSelection Members
/// <summary>
/// Dimension of data
/// </summary>
public int DataDimension
{
get
{
return points.Count;
}
}
/// <summary>
/// Access to n - th element
/// </summary>
double? IStructuredSelection.this[int n]
{
get
{
return this[n, 1];
}
}
/// <summary>
/// Weight of n - th element
/// </summary>
/// <param name="n">Element number</param>
/// <returns>The weight</returns>
public double GetWeight(int n)
{
return 1;
}
/// <summary>
/// Aprior weight of n - th element
/// </summary>
/// <param name="n">Element number</param>
/// <returns>The weight</returns>
public double GetApriorWeight(int n)
{
return 1;
}
/// <summary>
/// Tolerance of it - th element
/// </summary>
/// <param name="n">Element number</param>
/// <returns>Tolerance</returns>
public int GetTolerance(int n)
{
return 1;
}
/// <summary>
/// Sets tolerance of n - th element
/// </summary>
/// <param name="n">Element number</param>
/// <param name="tolerance">Tolerance to set</param>
public void SetTolerance(int n, int tolerance)
{
}
/// <summary>
/// The "is fixed amount" sign
/// </summary>
public bool HasFixedAmount
{
get
{
return true;
}
}
string IStructuredSelection.Name
{
get
{
return "Y";
}
}
/// <summary>
/// Count of points
/// </summary>
public int PointsCount
{
get
{
return points.Count;
}
}
/// <summary>
/// Free variables
/// </summary>
public string[] Variables
{
get
{
return var;
}
}
/// <summary>
/// Dimension of output vector
/// </summary>
public int VectorDimension
{
get
{
return 1;
}
}
#endregion
#region IStructuredSelectionCollection Members
int IStructuredSelectionCollection.Count
{
get
{
return 2;
}
}
IStructuredSelection IStructuredSelectionCollection.this[int i]
{
get
{
return selections[i];
}
}
#endregion
/// <summary>
/// Access to value of function and its derivation
/// </summary>
public double[] this[double x]
{
get
{
if (this[0, 0] > x)
{
//throw new Exception("Argument too small");
parameter[0] = this[0, 1];
parameter[1] = 0;
return parameter;
}
if (this[Count - 1, 0] < x)
{
//throw new Exception("Argument too large");
parameter[0] = this[Count - 1, 1];
parameter[1] = 0;
return parameter;
}
if (step != 0)
{
int i = (int)(Math.Floor((x - this[0, 0]) / step));
if (i == Count - 1)
{
--i;
}
double x1 = this[i, 0];
double x2 = this[i + 1, 0];
double y1 = this[i, 1];
double y2 = this[i + 1, 1];
parameter[1] = (y2 - y1) / (x2 - x1);
parameter[0] = y1 + parameter[1] * (x - x1);
return parameter;
}
for (int i = 1; i < Count; i++)
{
double x2 = this[i, 0];
if (x2 > x)
{
double x1 = this[i - 1, 0];
double y1 = this[i - 1, 1];
double y2 = this[i, 1];
parameter[1] = (y2 - y1) / (x2 - x1);
parameter[0] = y1 + parameter[1] * (x - x1);
break;
}
}
return parameter;
}
}
public string X
{
get
{
return x;
}
set
{
x = value;
}
}
public string Y
{
get
{
return y;
}
set
{
y = value;
}
}
#region IArgumentSelection Members
/// <summary>
/// Calculates synchronized selection
/// </summary>
/// <param name="selection">The etalon selection</param>
/// <returns>Synchronized selection</returns>
public IArgumentSelection SynchronizedSelection(IArgumentSelection selection)
{
if (!(selection is SeriesBase))
{
throw new Exception("Incompatible selections");
}
SeriesBase etalon = selection as SeriesBase;
SeriesBase s = new SeriesBase();
for (int i = 0; i < etalon.PointsCount; i++)
{
double x = etalon[i, 0];
double a = this[0, 0];
if (x < a)
{
s.AddXY(x, this[0, 1]);
continue;
}
double b = this[PointsCount - 1, 0];
if (x > b)
{
s.AddXY(x, this[PointsCount - 1, 1]);
continue;
}
s.AddXY(x, this[x][1]);
}
return s;
}
/// <summary>
/// Gets value of variable
/// </summary>
double IArgumentSelection.this[int i, string str]
{
get
{
return this[i, 0];
}
}
#endregion
/// <summary>
/// Creates inverted series
/// </summary>
/// <param name="step">Step</param>
/// <returns>Inverted series</returns>
public SeriesBase CreareInvertedSeries(double step)
{
if (IsIncreasing)
{
return CreateIncreasingInvertedSeries(step);
}
return CreateDecreasingInvertedSeries(step);
}
/// <summary>
/// Creates increasing inverted series
/// </summary>
/// <param name="step">Step</param>
/// <returns>Inverted series</returns>
public SeriesBase CreateIncreasingInvertedSeries(double step)
{
List<double[]> l = Points;
double[] p = l[0];
double y1 = p[1];
double[] p1 = l[l.Count - 1];
double y2 = p1[1];
SeriesBase sb = new SeriesBase();
for (int i = 0; ; i++)
{
double yy = y1 + i * step;
if (yy > y2)
{
sb.AddXY(y2, p1[0]);
break;
}
double x = CaclulateIncreasingInvertedFunction(l, yy);
sb.AddXY(yy, x);
}
return sb;
}
/// <summary>
/// Creates decreasing inverted series
/// </summary>
/// <param name="step">Step</param>
/// <returns>Inverted series</returns>
public SeriesBase CreateDecreasingInvertedSeries(double step)
{
List<double[]> l = Points;
double[] p = l[0];
double y1 = p[1];
double[] p1 = l[l.Count - 1];
double y2 = p1[1];
SeriesBase sb = new SeriesBase();
for (int i = 0; ; i++)
{
double yy = y2 + i * step;
if (yy > y2)
{
sb.AddXY(y2, p[0]);
break;
}
double x = CaclulateDecreasingInvertedFunction(l, yy);
sb.AddXY(yy, x);
}
return sb;
}
/// <summary>
/// Calculates value of equal step
/// </summary>
/// <param name="x">Argument</param>
/// <returns>Value</returns>
public double CalculateEqualStep(double x)
{
List<double[]> l = Points;
double x1 = l[0][0];
double x2 = l[1][0];
double s = x2 = x1;
double dx = (x - x1) / s;
int n = (int)dx;
if (n >= l.Count)
{
return l[l.Count - 1][1];
}
return LinearInterpolation(x, l[n], l[n + 1]);
}
/// <summary>
/// The is increasing sign
/// </summary>
public virtual bool IsIncreasing
{
get
{
List<double[]> l = Points;
double[] p1 = l[0];
double[] p2 = l[l.Count - 1];
double y1 = p1[1];
double y2 = p2[1];
return y2 > y1;
}
}
/// <summary>
/// Inverted function
/// </summary>
/// <param name="x">Argument</param>
/// <returns>Value of inverted function</returns>
public virtual double InvertedFunction(double x)
{
return InvertedFunction(Points, x);
}
/// <summary>
/// Inverted function
/// </summary>
/// <param name="l">Values</param>
/// <param name="x">Argument</param>
/// <returns>Value of inverted function</returns>
public static double InvertedFunction(List<double[]> l, double x)
{
double[] p1 = l[0];
double[] p2 = l[l.Count - 1];
double y1 = p1[1];
double y2 = p2[1];
if (y2 > y1)
{
return CaclulateIncreasingInvertedFunction(l, x);
}
return CaclulateDecreasingInvertedFunction(l, x);
}
/// <summary>
/// Calculates increasing inverted function
/// </summary>
/// <param name="l">Values</param>
/// <param name="x">Argument</param>
/// <returns>Value of inverted function</returns>
public static double CaclulateIncreasingInvertedFunction(IList<double[]> l, double y)
{
double[] p = l[0];
for (int i = 1; i < l.Count; i++)
{
double[] p1 = l[i];
if (y < p1[1])
{
return LinearInterpolation(y, p, p1);
}
p = p1;
}
return 0;
}
/// <summary>
/// Calculates increasing inverted function
/// </summary>
/// <param name="l">Values</param>
/// <param name="x">Argument</param>
/// <returns>Value of inverted function</returns>
public static double CaclulateDecreasingInvertedFunction(IList<double[]> l, double y)
{
double[] p = l[l.Count - 1];
for (int i = l.Count - 2; i >= 0; i--)
{
double[] p1 = l[i];
if (y > p1[1])
{
return LinearInterpolation(y, p, p1);
}
p = p1;
}
return 0;
}
/// <summary>
/// Linear interpolation
/// </summary>
/// <param name="x">Argument</param>
/// <param name="x1">x1</param>
/// <param name="y1">y1</param>
/// <param name="x2">x2</param>
/// <param name="y2">y2</param>
/// <returns>Interpolated value</returns>
public static double LinearInterpolation(double x, double x1, double y1, double x2, double y2)
{
return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1));
}
/// <summary>
/// Linear interpolation
/// </summary>
/// <param name="x">Argument</param>
/// <param name="p1">Point 1</param>
/// <param name="p2">Point 2</param>
/// <returns>Interpolated value</returns>
public static double LinearInterpolation(double x, double[] p1, double[] p2)
{
return LinearInterpolation(x, p1[0], p1[1], p2[0], p2[1]);
}
/// <summary>
/// Initialization of mesurements
/// </summary>
protected virtual void InitialzeMeasurements()
{
if (meaX.Length == points.Count)
{
return;
}
meaX = new object[points.Count];
meaY = new object[meaX.Length];
type = new object[meaX.Length];
for (int i = 0; i < meaX.Length; i++)
{
meaX[i] = this[i, 0];
meaY[i] = this[i, 1];
}
Double a = 0;
type = new ArrayReturnType(a, new int[] { points.Count }, true);
}
private object parX()
{
InitialzeMeasurements();
return meaX;
}
private object parY()
{
InitialzeMeasurements();
return meaY;
}
/// <summary>
/// Checks whether series has equal step
/// </summary>
private void checkEqualStep()
{
if (points.Count < 2)
{
return;
}
double s = 0;
double t = 0;
for (int i = 0; i < points.Count; i++)
{
double[] p = points[i] as double[];
if (i == 1)
{
s = p[0] - t;
}
if (i > 1)
{
if (Math.Abs(s - (p[0] - t)) > (eps * Math.Abs(s)))
{
return;
}
}
t = p[0];
}
step = s;
}
/// <summary>
/// Initialization
/// </summary>
protected virtual void initialize()
{
initMeasures();
points = new List<double[]>();
pointStart = new int[2];
pointFinish = new int[2];
}
protected void Post()
{
initMeasures();
measureY = YMeasure.getMeasure(this);
meas[1] = measureY;
selections = new IStructuredSelection[] { new XSelection(this), this };
checkEqualStep();
}
private void initMeasures()
{
measureParameter[0] = new Func<object>(parX);
measureParameter[1] = new Func<object>(parY);
IMeasure[] m = EndPointMeasure.CreateMeasurements(this);
meas[0] = this;
for (int i = 0; i < m.Length; i++)
{
meas[i + 2] = m[i];
}
}
#endregion
#region IAliasVector Members
IList<string> IAliasVector.AliasNames
{
get { return vectorNames; }
}
object IAliasVector.this[string name, int i]
{
get
{
return points[i][1];
}
set
{
points[i][1] = (double)value;
}
}
object IAliasVector.GetType(string name)
{
return a;
}
int IAliasVector.GetCount(string name)
{
return points.Count;
}
#endregion
#region Helper Classes
class EndPointMeasure : IMeasure
{
#region Fields
private SeriesBase s;
private string name;
private Func<object> par;
private const Double a = 0;
#endregion
#region Ctor
private EndPointMeasure(int[] b, SeriesBase s)
{
this.s = s;
if (b[0] == 0)
{
name = "X_" + (b[1] + 1);
if (b[1] == 0)
{
par = x1;
return;
}
par = x2;
return;
}
name = "Y_" + (b[1] + 1);
if (b[1] == 0)
{
par = y1;
return;
}
par = y2;
}
#endregion
#region Members
internal static IMeasure[] CreateMeasurements(SeriesBase s)
{
List<IMeasure> l = new List<IMeasure>();
int[] b = new int[2];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
b[0] = j;
b[1] = i;
l.Add(new EndPointMeasure(b, s));
}
}
return l.ToArray();
}
object x1()
{
double a = 0;
if (s.points.Count > 0)
{
return s.points[0][0];
}
return a;
}
object y1()
{
double a = 0;
if (s.points.Count > 0)
{
return s.points[0][1];
}
return a;
}
object x2()
{
double a = 0;
if (s.points.Count > 0)
{
return s.points[s.points.Count - 1][0];
}
return a;
}
object y2()
{
double a = 0;
if (s.points.Count > 0)
{
return s.points[s.points.Count - 1][1];
}
return a;
}
#endregion
#region IMeasure Members
Func<object> IMeasure.Parameter
{
get { return par; }
}
string IMeasure.Name
{
get { return name; }
}
object IMeasure.Type
{
get { return a; }
}
#endregion
}
class YMeasure : IMeasure
{
private SeriesBase s;
public static IMeasure getMeasure(SeriesBase s)
{
return new YMeasure(s);
}
YMeasure(SeriesBase s)
{
this.s = s;
}
#region IMeasure Members
public Func<object> Parameter
{
get
{
return s.measureParameter[1];
}
}
public Func<object> Derivation
{
get
{
return null;
}
}
public string Name
{
get
{
return "Y";
}
}
public double Factor
{
get
{
return 1;
}
}
public object Type
{
get
{
return s.Type;
}
}
#endregion
}
class XSelection : IStructuredSelection
{
private SeriesBase s;
#region IStructuredSelection Members
public XSelection(SeriesBase s)
{
this.s = s;
}
/// <summary>
/// Dimension of data
/// </summary>
public int DataDimension
{
get
{
return s.points.Count;
}
}
/// <summary>
/// Access to n - th element
/// </summary>
double? IStructuredSelection.this[int n]
{
get
{
return s[n, 0];
}
}
/// <summary>
/// Weight of n - th element
/// </summary>
/// <param name="n">Element number</param>
/// <returns>The weight</returns>
public double GetWeight(int n)
{
return 1;
}
/// <summary>
/// Aprior weight of n - th element
/// </summary>
/// <param name="n">Element number</param>
/// <returns>The weight</returns>
public double GetApriorWeight(int n)
{
return 1;
}
/// <summary>
/// Tolerance of it - th element
/// </summary>
/// <param name="n">Element number</param>
/// <returns>Tolerance</returns>
public int GetTolerance(int n)
{
return 1;
}
/// <summary>
/// Sets tolerance of n - th element
/// </summary>
/// <param name="n">Element number</param>
/// <param name="tolerance">Tolerance to set</param>
public void SetTolerance(int n, int tolerance)
{
}
/// <summary>
/// The "is fixed amount" sign
/// </summary>
public bool HasFixedAmount
{
get
{
return true;
}
}
/// <summary>
/// Count of points
/// </summary>
public int PointsCount
{
get
{
return s.points.Count;
}
}
/// <summary>
/// Free variables
/// </summary>
public string[] Variables
{
get
{
return s.var;
}
}
/// <summary>
/// Dimension of output vector
/// </summary>
public int VectorDimension
{
get
{
return 1;
}
}
public string Name
{
get
{
return "X";
}
}
#endregion
}
#endregion
}
}