using Backend;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Frontend
{
class WaveFormChart : Panel
{
/*************************************************************************/
/* 設定定数
/*************************************************************************/
public static int NDATA = 500; //ろうそく足の本数
public static Padding mrgn = new Padding(10, 10, 50, 30); // [サイズ] Chart1のグラフマージン
protected static int horzMrgn = mrgn.Left + mrgn.Right; // マージン
protected static int vertMrgn = mrgn.Top + mrgn.Bottom;
protected static Font font = new Font("Arial", 7); // フォント1
protected static Font font2 = new Font("Arial", 7); // フォント2
protected static Pen penRed = new Pen(Color.Red, 2);
protected static Pen penBlue = new Pen(Color.Blue, 2);
protected static Pen penGrayDot = new Pen(Color.Gray, 1) { DashStyle = DashStyle.Dot }; // 罫線点線
/*************************************************************************/
/* コントロール系変数
/*************************************************************************/
/* メンバ */
protected int nBgn; // 表示する先頭レコード番号 [0, data.Length-NDATA]
/* オプション */
protected static TextFormatFlags mid = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter; // センター寄オプション
protected static TextFormatFlags left = TextFormatFlags.Left | TextFormatFlags.VerticalCenter; // センター寄オプション
protected double[] Tick = {1e-8, 5e-8, 1e-7, 5e-7, 1e-6, 5e-6, 1e-5, 5e-5,
1e-4, 5e-4, 1e-3, 5e-3, 1e-2, 5e-2, 1e-1, 5e-1, 1, 2, 5, 10, 20, 50, 100, 200, 500,1000, 10000, 20000, 50000 };
protected Rectangle MainChartRect; // Chart1とChart2をあわせたRectangle
/* グラフのレンジ */
protected double xMin = double.MaxValue;
protected double xMax = double.MinValue;
protected double yMin = double.MaxValue;
protected double yMax = double.MinValue;
protected double xTickValue = 0; // 一目盛りの大きさ
protected double yTickValue = 0; // 一目盛りの大きさ
public string XLabel { set; get; }
public string YLabel { set; get; }
public string Title { set; get; }
protected bool IsMouseDraging = false;
/*************************************************************************
* 座標変換
*************************************************************************/
/// <summary> グラフ座標からウィンドウ座標へ変換 </summary>
/// <param name="x">グラフ座標上の正規化された位置(0~1)</param>
/// <returns>パネル内のピクセル値</returns>
int nx(double x)
{
return (int)(MainChartRect.Left + x * MainChartRect.Width);
}
/// <summary>グラフ座標からウィンドウ座標へ変換</summary>
/// <param name="y">グラフ座標上の正規化された位置(0~1)</param>
/// <returns>パネル内のピクセル値</returns>
int ny(double y)
{
return (int)(MainChartRect.Top + (1.0 - y) * MainChartRect.Height);
}
double normX(double x)
{
return (x - xMin) / (xMax - xMin);
}
double normY(double y)
{
return (y - yMin) / (yMax - yMin);
}
/*************************************************************************
* コンストラクタ
*************************************************************************/
/// <summary>
/// コンストラクタ
/// </summary>
public WaveFormChart()
{
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.DoubleBuffered = true; // ダブルバッファリング: ちらつき防止
this.Size = new Size(600, 400);
// マウスイベント
this.MouseMove += new MouseEventHandler(mouseMove);
this.MouseDown += new MouseEventHandler(mouseDown);
this.MouseUp += new MouseEventHandler(mouseUp);
this.MouseWheel += new MouseEventHandler(mouserWheel);
}
/*************************************************************************
* プロットデータ
*************************************************************************/
/// <summary>
/// プロットする打音
/// </summary>
protected DaonPlotData TargetDaon = null;
/// <summary>
/// プロット用の打音データ
/// </summary>
public class DaonPlotData
{
public Daon Daon { set; get; }
public float[] X { set; get; }
public float[] Y { set; get; }
}
/// <summary>
/// チャートデータのセット
/// </summary>
public void AddXY(float[] x, float[] y, Daon daon)
{
TargetDaon = new DaonPlotData() { Daon = daon, X = x, Y = y };
this.Refresh();
}
/// <summary>
/// データのクリア
/// </summary>
public void Clear()
{
TargetDaon = null;
this.Refresh();
}
/*************************************************************************
* マウスイベント
*************************************************************************/
private void mouseMove(object sender, MouseEventArgs e)
{
}
private void mouseDown(object sender, MouseEventArgs e)
{
}
private void mouseUp(object sender, MouseEventArgs e)
{
}
private void mouserWheel(object sender, MouseEventArgs e)
{
}
/*************************************************************************
* シーケンス関数
*************************************************************************/
void CalcXYRange()
{
/* 最大最小の計算 */
xMax = double.MinValue;
xMin = double.MaxValue;
yMax = double.MinValue;
yMin = double.MaxValue;
for (int n = 0; n < TargetDaon.X.Length; n++)
{
xMax = Math.Max(xMax, TargetDaon.X[n]);
xMin = Math.Min(xMin, TargetDaon.X[n]);
yMax = Math.Max(yMax, TargetDaon.Y[n]);
yMin = Math.Min(yMin, TargetDaon.Y[n]);
}
// スケール
double xRange = xMax - xMin;
double yRange = yMax - yMin;
//xMax = xMax + xRange * 0.1;
//xMin = xMin - xRange * 0.1;
//yMax = yMax + yRange * 0.1;
//yMin = yMin - yRange * 0.1;
yMax = 1.1;
yMin = -1.1;
// X最大・最小を計算
for (int i = 0; i < Tick.Length; i++)
{
// 7本分ぐらいのTick(幅)を選択
if (7 * Tick[i] < (xMax - xMin))
xTickValue = Tick[i];
else
continue;
}
// Tick単位の大きさに変更
xMax = Math.Ceiling(xMax / xTickValue) * xTickValue; // 大きい側を使用
xMin = Math.Floor(xMin / xTickValue) * xTickValue; // 小さい側を使用
// Y最大・最小を計算
for (int i = 0; i < Tick.Length; i++)
{
// 7本分ぐらいのTick(幅)を選択
if (4 * Tick[i] < (yMax - yMin))
yTickValue = Tick[i];
else
continue;
}
// Tick単位の大きさに変更
yMax = Math.Ceiling(yMax / yTickValue) * yTickValue; // 大きい側を使用
yMin = Math.Floor(yMin / yTickValue) * yTickValue; // 小さい側を使用
}
void drawXLine(Graphics g)
{
// X軸の目盛りの数
int numTicks = (int)((xMax - xMin) / xTickValue);
for (int n = 0; n < numTicks; n++)
{
double _x = (double)n / (numTicks - 1); // 正規化
// X軸の罫線の描画
if (n > 0 && n < numTicks - 1)
{
g.DrawLine(penGrayDot, nx(_x), ny(0), nx(_x), ny(1));
}
// X軸の目盛り文字
Rectangle RC_DateText = new Rectangle(nx(_x) - 15 - (n == (numTicks - 1) ? 5 : 0), ny(0), 30, 20);
string dateString = $"{n * xTickValue + xMin}";
TextRenderer.DrawText(g, dateString, font, RC_DateText, Color.Black, mid);
}
}
/// <summary>
/// Y罫線のびょうが
/// </summary>
void drawYLine(Graphics g)
{
// Y軸の目盛りの数
int numTicks = (int)((yMax - yMin) / yTickValue);
for (int n = 0; n < numTicks; n++)
{
double _y = (double)n / (numTicks - 1); // 正規化
//Y軸の罫線の描画
if (0 < n && n < numTicks)
{
g.DrawLine(penGrayDot, nx(0), ny(_y), nx(1), ny(_y));
}
// Y軸の目盛り文字
var RectTitle = new Rectangle(nx(1), ny(_y) - (n > 0 ? 10 : 14), 50, 20);
string num = (yMin + n * yTickValue).ToString();
TextRenderer.DrawText(g, num, font, RectTitle, Color.Black, left);
}
}
/*************************************************************************
* 再描画メソッド
*************************************************************************/
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
// グラフ(2つあわせた)サイズ ※リサイズのたびに作り直される
MainChartRect = new Rectangle(mrgn.Left, mrgn.Top, ClientSize.Width - horzMrgn, ClientSize.Height - vertMrgn);
/* チャートの外枠を表示 */
Rectangle RCChart1 = new Rectangle(nx(0), ny(1), nx(1) - nx(0), ny(0) - ny(1));
g.FillRectangle(Brushes.White, RCChart1);
g.DrawRectangle(Pens.Black, RCChart1);
/* チャートの外枠を表示 */
int margin = 3;
Rectangle RCChartOuter = new Rectangle(0 + margin, 0 + margin, ClientSize.Width - 2 * margin, ClientSize.Height - 2 * margin);
g.DrawRectangle(Pens.Black, RCChartOuter);
// もしデータが無い場合は処理無し
if (TargetDaon == null) return;
/* 最大最小の再計算 */
this.CalcXYRange();
/***********************/
/* x軸罫線,目盛り描画 */
/***********************/
this.drawXLine(g);
/***********************/
/* Y軸罫線,目盛りの描画 */
/***********************/
this.drawYLine(g);
/***********************/
/* 信号をプロット */
/***********************/
int Nx = TargetDaon.X.Length;
int Ny = TargetDaon.Y.Length;
if (Nx != Ny)
throw new ArgumentOutOfRangeException();
for (int i = 1; i < Ny; i++)
{
int x1 = nx(normX(TargetDaon.X[i - 1]));
int y1 = ny(normY(TargetDaon.Y[i - 1]));
int x2 = nx(normX(TargetDaon.X[i]));
int y2 = ny(normY(TargetDaon.Y[i]));
g.DrawLine(Pens.Blue, new Point(x1, y1), new Point(x2, y2));
}
}
}
}