728x90
반응형
728x170
▶ MathHelper.cs
using System;
using System.Collections.Generic;
using System.Drawing;
namespace TestProject
{
/// <summary>
/// 수학 헬퍼
/// </summary>
public class MathHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 제곱 오차 구하기 - GetErrorSquared(pointList, a, b)
/// <summary>
/// 제곱 오차 구하기
/// </summary>
/// <param name="pointList">포인트 리스트</param>
/// <param name="a">A</param>
/// <param name="b">B</param>
/// <returns>제곱 오차</returns>
public static double GetErrorSquared(List<PointF> pointList, double a, double b)
{
double result = 0;
foreach(PointF point in pointList)
{
double error = point.Y - (a * point.X + b);
result += error * error;
}
return result;
}
#endregion
#region 선형 최소 제곱법 해 구하기 - GetLinearLeastSquaresFit(pointList, a, b)
/// <summary>
/// 선형 최소 제곱법 해 구하기
/// </summary>
/// <param name="pointList">포인트 리스트</param>
/// <param name="a">A</param>
/// <param name="b">B</param>
/// <returns>오차</returns>
public static double GetLinearLeastSquaresFit(List<PointF> pointList, out double a, out double b)
{
double count = pointList.Count;
double xSummary = 0;
double ySummary = 0;
double xxSummary = 0;
double xySummary = 0;
foreach(PointF point in pointList)
{
xSummary += point.X;
ySummary += point.Y;
xxSummary += point.X * point.X;
xySummary += point.X * point.Y;
}
a = (xySummary * count - xSummary * ySummary) / (xxSummary * count - xSummary * xSummary);
b = (xySummary * xSummary - ySummary * xxSummary) / (xSummary * xSummary - count * xxSummary);
return Math.Sqrt(GetErrorSquared(pointList, a, b));
}
#endregion
}
}
728x90
▶ MainForm.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace TestProject
{
/// <summary>
/// 메인 폼
/// </summary>
public partial class MainForm : Form
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// X 최소값
/// </summary>
private const float X_MINIMUM = -10.0f;
/// <summary>
/// X 최대값
/// </summary>
private const float X_MAXIMUM = 10.0f;
/// <summary>
/// Y 최소값
/// </summary>
private const float Y_MINIMUM = -10.0f;
/// <summary>
/// Y 최대값
/// </summary>
private const float Y_MAXIMUM = 10.0f;
/// <summary>
/// 그리기 변환
/// </summary>
private Matrix drawingTransform;
/// <summary>
/// 반전 변환
/// </summary>
private Matrix inverseTransform;
/// <summary>
/// 포인트 리스트
/// </summary>
private List<PointF> pointList = new List<PointF>();
/// <summary>
/// 솔루션 여부
/// </summary>
private bool hasSolution = false;
/// <summary>
/// 최적 A
/// </summary>
private double bestA;
/// <summary>
/// 최적 B
/// </summary>
private double bestB;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
#region 이벤트를 설정한다.
Load += Form_Load;
this.calculateButton.Click += calculateButton_Click;
this.clearButton.Click += clearButton_Click;
this.graphButton.Click += graphButton_Click;
this.graphPictureBox.MouseClick += graphPictureBox_MouseClick;
this.graphPictureBox.Paint += graphPictureBox_Paint;
#endregion
}
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Private
//////////////////////////////////////////////////////////////////////////////// Event
#region 폼 로드시 처리하기 - Form_Load(sender, e)
/// <summary>
/// 폼 로드시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void Form_Load(object sender, EventArgs e)
{
RectangleF worldRectangle = new RectangleF
(
X_MINIMUM,
Y_MINIMUM,
X_MAXIMUM - X_MINIMUM,
Y_MAXIMUM - Y_MINIMUM
);
PointF[] pointArray =
{
new PointF(0, graphPictureBox.ClientSize.Height),
new PointF(graphPictureBox.ClientSize.Width, graphPictureBox.ClientSize.Height),
new PointF(0, 0),
};
this.drawingTransform = new Matrix(worldRectangle, pointArray);
this.inverseTransform = this.drawingTransform.Clone();
this.inverseTransform.Invert();
}
#endregion
#region 계산하기 버튼 클릭시 처리하기 - calculateButton_Click(sender, e)
/// <summary>
/// 계산하기 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void calculateButton_Click(object sender, EventArgs e)
{
Cursor = Cursors.WaitCursor;
this.aTextBox.Clear();
this.bTextBox.Clear();
this.errorTextBox.Clear();
Application.DoEvents();
MathHelper.GetLinearLeastSquaresFit(this.pointList, out this.bestA, out this.bestB);
this.hasSolution = true;
this.aTextBox.Text = this.bestA.ToString();
this.bTextBox.Text = this.bestB.ToString();
ShowError();
this.hasSolution = true;
this.graphPictureBox.Refresh();
Cursor = Cursors.Default;
}
#endregion
#region 지우기 버튼 클릭시 처리하기 - clearButton_Click(sender, e)
/// <summary>
/// 지우기 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void clearButton_Click(object sender, EventArgs e)
{
this.pointList = new List<PointF>();
this.hasSolution = false;
this.graphPictureBox.Refresh();
this.aTextBox.Clear();
this.bTextBox.Clear();
this.errorTextBox.Clear();
}
#endregion
#region 그래프 버튼 클릭시 처리하기 - graphButton_Click(sender, e)
/// <summary>
/// 그래프 버튼 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void graphButton_Click(object sender, EventArgs e)
{
this.bestA = double.Parse(this.aTextBox.Text);
this.bestB = double.Parse(this.bTextBox.Text);
ShowError();
this.graphPictureBox.Refresh();
}
#endregion
#region 그래프 픽처 박스 마우스 클릭시 처리하기 - graphPictureBox_MouseClick(sender, e)
/// <summary>
/// 그래프 픽처 박스 마우스 클릭시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void graphPictureBox_MouseClick(object sender, MouseEventArgs e)
{
PointF[] pointArray =
{
new PointF(e.X, e.Y)
};
this.inverseTransform.TransformPoints(pointArray);
this.pointList.Add(pointArray[0]);
this.graphPictureBox.Refresh();
}
#endregion
#region 그래프 픽처 박스 페인트시 처리하기 - graphPictureBox_Paint(sender, e)
/// <summary>
/// 그래프 픽처 박스 페인트시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void graphPictureBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Transform = this.drawingTransform;
DrawAxe(e.Graphics);
if(this.hasSolution)
{
using(Pen pen = new Pen(Color.Blue, 0))
{
double y0 = this.bestA * X_MINIMUM + this.bestB;
double y1 = this.bestA * X_MAXIMUM + this.bestB;
e.Graphics.DrawLine
(
pen,
(float)X_MINIMUM,
(float)y0,
(float)X_MAXIMUM,
(float)y1
);
}
}
float deltaX = (X_MAXIMUM - X_MINIMUM) / 200;
float deltaY = (Y_MAXIMUM - Y_MINIMUM) / 200;
using(Pen pen = new Pen(Color.Black, 0))
{
foreach(PointF point in this.pointList)
{
e.Graphics.FillRectangle
(
Brushes.White,
point.X - deltaX,
point.Y - deltaY,
2 * deltaX,
2 * deltaY
);
e.Graphics.DrawRectangle
(
pen,
point.X - deltaX,
point.Y - deltaY,
2 * deltaX,
2 * deltaY
);
}
}
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Function
#region 축 그리기 - DrawAxe(graphics)
/// <summary>
/// 축 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
private void DrawAxe(Graphics graphics)
{
using(Pen pen = new Pen(Color.Black, 0))
{
const float xThick = 0.2f;
const float yThick = 0.2f;
graphics.DrawLine(pen, X_MINIMUM, 0, X_MAXIMUM, 0);
for(float x = X_MINIMUM; x <= X_MAXIMUM; x += 1.0f)
{
graphics.DrawLine(pen, x, -yThick, x, yThick);
}
graphics.DrawLine(pen, 0, Y_MINIMUM, 0, Y_MAXIMUM);
for(float y = Y_MINIMUM; y <= Y_MAXIMUM; y += 1.0f)
{
graphics.DrawLine(pen, -xThick, y, xThick, y);
}
}
}
#endregion
#region 오차 보여주기 - ShowError()
/// <summary>
/// 오차 보여주기
/// </summary>
private void ShowError()
{
double error = Math.Sqrt(MathHelper.GetErrorSquared(this.pointList, this.bestA, this.bestB));
this.errorTextBox.Text = error.ToString();
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] TabControl 클래스 : 사용자 정의 그리기 (0) | 2018.12.22 |
---|---|
[C#/WINFORM] 실시간 그래프 그리기 (0) | 2018.12.21 |
[C#/WINFORM] 타원과 타원 교차점 구하기 (0) | 2018.12.21 |
[C#/WINFORM] PictureBox 클래스 : SizeMode 속성에 따라 이미지 구하기 (0) | 2018.12.19 |
[C#/WINFORM] 다항식 최소 제곱법(Polynomial Least Squares Method) 사용하기 (0) | 2018.12.19 |
[C#/WINFORM] ColorDialog 클래스 : 커스텀 색상 사용하기 (0) | 2018.12.19 |
[C#/WINFORM] ImageAttributes 클래스 : 무지개 색상 이미지 구하기 (0) | 2018.12.19 |
[C#/WINFORM] ImageAttributes 클래스 : 색상 이미지 구하기 (0) | 2018.12.19 |
[C#/WINFORM] ImageAttributes 클래스 : 채널 이미지 구하기 (0) | 2018.12.18 |
[C#/WINFORM] ImageAttributes 클래스 : 세피아 이미지 구하기 (0) | 2018.12.18 |
댓글을 달아 주세요