/* * Karinto Library Project * * This software is distributed under a zlib-style license. * See license.txt for more information. */ using System; using System.Collections.Generic; using System.Data; namespace Karinto { public class PointList : List, ICloneable { #region properties /// /// 最初の点 /// public Point First { get { return this[0]; } } /// /// 最後の点 /// public Point Last { get { return this[this.Count - 1]; } } /// /// Xの配列 /// public double[] XArray { get { double[] array = new double[this.Count]; for (int i = 0; i < this.Count; ++i) { array[i] = this[i].X; } return array; } set { if (value.Length != this.Count) { throw new ArgumentException("The input array is too short or long."); } for (int i = 0; i < value.Length; ++i) { this[i].X = value[i]; } } } /// /// Yの配列 /// public double[] YArray { get { double[] array = new double[this.Count]; for (int i = 0; i < this.Count; ++i) { array[i] = this[i].Y; } return array; } set { if (value.Length != this.Count) { throw new ArgumentException("The input array is too short or long."); } for (int i = 0; i < value.Length; ++i) { this[i].Y = value[i]; } } } /// /// Xの最小値 /// public double XMin { get { double min = XArray[0]; foreach (Point p in this) { if (min > p.X) min = p.X; } return min; } } /// /// Xの最大値 /// public double XMax { get { double max = XArray[0]; foreach (Point p in this) { if (max < p.X) max = p.X; } return max; } } /// /// Yの最小値 /// public double YMin { get { double min = YArray[0]; foreach (Point p in this) { if (min > p.Y) min = p.Y; } return min; } } /// /// Yの最大値 /// public double YMax { get { double max = YArray[0]; foreach (Point p in this) { if (max < p.Y) max = p.Y; } return max; } } /// /// Xの平均 /// public double XAverage { get { double sum = 0.0; foreach (Point p in this) { sum += p.X; } return sum / this.Count; } } /// /// Yの平均 /// public double YAverage { get { double sum = 0.0; foreach (Point p in this) { sum += p.Y; } return sum / this.Count; } } /// /// Xの分散 /// public double XVariance { get { double avg = this.XAverage; double var = 0.0; foreach (Point d in this) { double dif = (d.X - avg); var += dif * dif; } return var / this.Count; } } /// /// Yの分散 /// public double YVariance { get { double avg = this.YAverage; double var = 0.0; foreach (Point d in this) { double dif = (d.Y - avg); var += dif * dif; } return var / this.Count; } } /// /// 共分散 /// public double Covariance { get { double avgX = this.XAverage; double avgY = this.YAverage; double var = 0.0; foreach (Point d in this) { var += (d.X - avgX) * (d.Y - avgY); } return var / this.Count; } } /// /// R2乗値 /// public double R2 { get { double cov = Covariance; double var = XVariance * YVariance; if (Math.Abs(cov) < Double.Epsilon && Math.Abs(var) < Double.Epsilon) { return 1.0; // とりあえず実質1点のみの場合は1 数学的には不定の方が正しい? } return cov * cov / var; } } /// /// Xの値域 /// public Range XRange { get { return new Range(XMin, XMax); } } /// /// Yの値域 /// public Range YRange { get { return new Range(YMin, YMax); } } /// /// 広義単調増加か否か /// public bool MonotonicallyIncreasing { get { PointList sorted = (PointList)Clone(); sorted.SortByX(); double yPrev = sorted.First.Y; for (int i = 1; i < Count; ++i) { double yCur = this[i].Y; if (yCur < yPrev) return false; yPrev = yCur; } return true; } } /// /// 広義単調減少か否か /// public bool MonotonicallyDecreasing { get { PointList sorted = (PointList)Clone(); sorted.SortByX(); double yPrev = sorted.First.Y; for (int i = 1; i < Count; ++i) { double yCur = this[i].Y; if (yCur > yPrev) return false; yPrev = yCur; } return true; } } #endregion #region constructors public PointList() : base() { } public PointList(PointList points) : base(points.Count) { foreach (Point p in points) { this.Add(new Point(p)); } } public PointList(Point[] points) : base(points.Length) { foreach (Point p in points) { this.Add(new Point(p)); } } public PointList(double[] xArray, double[] yArray) : base(xArray.Length) { if (xArray.Length != yArray.Length) { throw new ArgumentException("xArray and yArray must be same length"); } for (int i = 0; i < xArray.Length; ++i) { this.Add(xArray[i], yArray[i]); } } public PointList(FilePath path) { CsvReader reader = new CsvReader(); List points = reader.Read(path); foreach (Point p in points) { this.Add(new Point(p)); } } #endregion #region public methods /// /// 点を追加 /// /// 点のx値 /// 点のy値 public void Add(double x, double y) { this.Add(new Point(x, y)); } public Object Clone() { return (Object)new PointList(this); } /// /// Xの値で昇順に並び変える /// public void SortByX() { Sort(Point.XComparer); } /// /// Yの値で昇順に並び変える /// public void SortByY() { Sort(Point.YComparer); } /// /// 点列の各要素を定数倍する /// /// x,yそれぞれに掛ける係数からなる点 public void Stretch(Point scale) { for (int i = 0; i < Count; ++i) { this[i] = this[i].Stretch(scale); } } public void SwapXY() { for (int i = 0; i < Count; ++i) { this[i].SwapXY(); } } public DataTable ToDataTable() { DataTable table = new Xml.Data.PointListDataTable(); for (int i = 0; i < Count; ++i) { Xml.Data.PointListRow row = table.NewRow() as Xml.Data.PointListRow; row.X = this[i].X; row.Y = this[i].Y; table.Rows.Add(row); } return table; } #endregion } }