//------------------------------------------------------------------------------
//	描画の関係のメソッド
//
//		作成者：三上直樹，2023/04/03 作成，©三上直樹 2023
//------------------------------------------------------------------------------

using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

using Mikami.WindowsApplication;
using Mikami.GraphicsLib;

using static System.Math;

namespace FIR_Design_Remez
{
	public partial class Form1 : Form
	{
		// 振幅特性の表示（リニアスケールの場合）
		private void DrawLinear(Graphics gr, Font myFont, Brush myBrush)
		{
			// 座標軸と目盛の描画
			Pen penGray =new Pen(Color.DimGray);
			// x軸
			for (int n=0; n<=5; n++)
				gr.DrawLine(penGray, n*X_FR_, 0, n*X_FR_, 8*Y_DB_);
			// y軸
			for (int n=0; n<=8; n++)
				gr.DrawLine(penGray, 0, n*Y_DB_, 5*X_FR_, n*Y_DB_);
			DispChrLinear(gr, myFont, myBrush);

			// 振幅特性の描画
			gr.SmoothingMode = SmoothingMode.AntiAlias;
			gr.SetClip(new Rectangle(0, -DRAW_MAX_, 5*X_FR_, DRAW_MIN_));	// 描画範囲の指定

			int dBmin = int.Parse(comboBox1.Text.Trim("dB".ToCharArray()));
			float dy = Y_DB_/(float)(Abs(dBmin)/8.0);
			var y_k = logA_k_.Select((x, n) => new PointF(dx_*n, -dy*x));
			Pen myPen = new Pen(Color.Navy, 2) { LineJoin = LineJoin.Round };
			gr.DrawLines(myPen, y_k.ToArray());				// 特性の描画

			// 遮断周波数の描画
			for (int k=0; k<2*nBand_; k++)
				if (bands_[k] != 0.0) DispFcLinear(gr, 1000*bands_[k], X_FR_, Y_DB_);

			gr.ResetClip();
		}
		
		// 遮断周波数の描画（リニアスケールの場合）
		private void DispFcLinear(Graphics gr, double fc, int Xfr, int YdB)
		{
			float x = (float)Round(10.0*Xfr*fc/(1000*fSkHz_));
			gr.DrawLine(Pens.Magenta, x, 0, x, 8*YdB);
		}

		// 座標軸の文字の描画（リニアスケールの場合）
		private void DispChrLinear(Graphics gr, Font myFont, Brush myBrush)
		{
			for (int n=0; n<=5; n++)
				gr.DrawString($"{(fSkHz_*n)/10.0, 6:F3}", myFont, myBrush, n*X_FR_-15, Y_DB_*8+4);

			DispChr(gr, myFont, myBrush);
		}

		// 横軸の周波数目盛を除く文字の描画（リニア，ログ共通）
		private void DispChr(Graphics gr, Font myFont, Brush myBrush, int yOrg = 0)
		{
			gr.TranslateTransform(0, yOrg);

			gr.DrawString("周波数 (kHz)", myFont, myBrush, 216, Y_DB_*8+22);

			gr.DrawString("0", myFont, myBrush, -14, -8);
			double dbWidth = Abs(int.Parse(comboBox1.Text.Replace("dB", "")));
			for (int n=1; n<=4; n++)
				gr.DrawString($"{-n*dbWidth/4.0, 3:F0}", myFont, myBrush, -26, 2*n*Y_DB_-8);

			gr.RotateTransform(-90);
			gr.DrawString("利得 (dB)", myFont, myBrush, -Y_DB_*4.5f, -48 );
			gr.RotateTransform(90);

			gr.TranslateTransform(0, -yOrg);
		}

		// 振幅特性の表示（ログスケールの場合）
		private void DrawLog(Graphics gr, Font myFont, Brush myBrush)
		{
			float dec_x = (float)(X_FR_*5/Log10(frqH_/frqL_));	// 横方向：10 倍に対するピクセル数
			int dBmin = int.Parse(comboBox1.Text.Replace("dB", ""));
			float dec_y = (float)(Y_DB_*2*80.0/Abs(dBmin));		// 縦方向：10 倍に対するピクセル数
			float min_y = (float)(Pow(10.0, dBmin/20.0));		// 縦方向：描画範囲の最小値
			float max_y = 1.0f;									// 縦方向：描画範囲の最大値

			LogScaleXY.Values xAxis = new LogScaleXY.Values(frqL_, frqH_, dec_x);
			LogScaleXY.Values yAxis = new LogScaleXY.Values(min_y, max_y, dec_y);

			gr.TranslateTransform(0, Y_DB_*8);
			yLog_ = new LogScaleXY(gr, xAxis, yAxis);

			// 座標軸と目盛の描画
			Pen penGray =new Pen(Color.DimGray);
			// x軸
			yLog_.DrawAxisX(penGray, Y_DB_*8, Y_DB_*8);
			// y軸
			yLog_.DrawAxisYdB(penGray, Abs(dBmin)/8.0f);
			DispChrLog(gr, frqL_, frqH_, yLog_, myFont, myBrush);

			// 振幅特性の描画
			Pen myPen = new Pen(Color.Navy, 2) { LineJoin = LineJoin.Round };
			double pi2OvFs = 2*PI/fSample_;
			yLog_.DrawLines(x => HwA(pi2OvFs*x), F_DIV_+1, myPen,
							-Y_DB_*8-4, Y_DB_*8+4);
			// 遮断周波数の描画
			for (int k=1; k<2*nBand_; k++)
				if (bands_[k] != fSkHz_/2) DispFcLog(gr, yLog_.X(1000*bands_[k]), Y_DB_);
		}

		// 表示周波数範囲の設定
		private void SetDisplayRange()
		{
			// カーソルで指定した周波数における利得の表示を一時的に禁止
			pictureBox1.MouseMove -= pictureBox1_MouseMove;
			
			if (!textBox4.ToFloat(
					out float tmp, v => (v > 0.0f) && (v < fSkHz_/2),
					"0 より大きく，標本化周波数/2 より小さくしてください．")) return;
			frqL_ = 1000*tmp;
			if (!textBox5.ToFloat(
					out tmp, v => (v > frqL_/1000.0f) && (v <= fSkHz_/2),
					"表示最低周波数 より大きく，標本化周波数/2 以下にしてください．"))　return;
			frqH_ = 1000*tmp;

			// カーソルで指定した周波数における利得の表示を復活
			pictureBox1.MouseMove += pictureBox1_MouseMove;
		}

		// 遮断周波数の描画（ログスケールの場合）
		private void DispFcLog(Graphics gr, float x, int YdB)
		{
			if ((x>0) && (x<5*X_FR_))
				gr.DrawLine(Pens.Magenta, x, 0, x, -8*YdB);
		}

		// 座標軸の文字の描画（ログスケールの場合）
		private void DispChrLog(Graphics gr, float frq1, float frq2, LogScaleXY yLog,
								Font myFont, Brush myBrush)
		{
			gr.DrawString($"{frq1/1.0E3, 6:F3}", myFont, myBrush, -15, 4);
			float frOk1 = frq1*1.25f;
			float frOk2 = frq2*0.7f;
			for (double x=Round(Log10(frq1)); x<=Round(Log10(frq2)); x+=1)
			{
				float fr = (float)Pow(10, x);
				
				if ((fr > frOk1) && (fr < frOk2))
					gr.DrawString($"{fr/1.0E3, 6:F3}", myFont, myBrush, yLog.X(fr)-18, 4);
				if ((fr*2 > frOk1) && (fr*2 < frOk2))
					gr.DrawString($"{2*fr/1.0E3, 6:F3}", myFont, myBrush, yLog.X(2*fr)-18, 4);
				if ((fr*5 > frOk1) && (fr*5 < frOk2))
					gr.DrawString($"{5*fr/1.0E3, 6:F3}", myFont, myBrush, yLog.X(5*fr)-18, 4);
			}
			gr.DrawString($"{frq2/1.0E3, 6:F3}", myFont, myBrush, 5*X_FR_-15, 4);

			DispChr(gr, myFont, myBrush, -Y_DB_*8);
		}
	}
}
