728x90
반응형
728x170
▶ Car.cs
using System.Drawing;
namespace TestProject
{
/// <summary>
/// 자동차
/// </summary>
public class Car
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 명칭
/// </summary>
public string Name;
/// <summary>
/// 색상
/// </summary>
public Color Color;
/// <summary>
/// 값 배열
/// </summary>
public float[] ValueArray;
/// <summary>
/// 포인트 배열
/// </summary>
public PointF[] PointArray = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - Car(name, color, valueArray)
/// <summary>
/// 생성자
/// </summary>
/// <param name="name">명칭</param>
/// <param name="color">색상</param>
/// <param name="valueArray">값 배열</param>
public Car(string name, Color color, params float[] valueArray)
{
Name = name;
Color = color;
ValueArray = (float[])valueArray.Clone();
}
#endregion
}
}
728x90
▶ Axis.cs
namespace TestProject
{
/// <summary>
/// 축
/// </summary>
public class Axis
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Public
#region Field
/// <summary>
/// 명칭
/// </summary>
public string Name;
/// <summary>
/// 포맷 문자열
/// </summary>
public string FormatString;
/// <summary>
/// 최소값
/// </summary>
public float Minimum;
/// <summary>
/// 최대값
/// </summary>
public float Maximum;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - Axis(name, formatString, minimum, maximum)
/// <summary>
/// 생성자
/// </summary>
/// <param name="name">명칭</param>
/// <param name="formatString">포맷 문자열</param>
/// <param name="minimum">최소값</param>
/// <param name="maximum">최대값</param>
public Axis(string name, string formatString, float minimum, float maximum)
{
Name = name;
FormatString = formatString;
Minimum = minimum;
Maximum = maximum;
}
#endregion
}
}
300x250
▶ MainForm.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
namespace TestProject
{
/// <summary>
/// 메인 폼
/// </summary>
public partial class MainForm : Form
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Field
////////////////////////////////////////////////////////////////////////////////////////// Private
#region Field
/// <summary>
/// 자동차 리스트
/// </summary>
private List<Car> carList = null;
/// <summary>
/// 축 리스트
/// </summary>
private List<Axis> axisList = null;
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - MainForm()
/// <summary>
/// 생성자
/// </summary>
public MainForm()
{
InitializeComponent();
Load += Form_Load;
this.fillAreaCheckBox.CheckedChanged += fillAreaCheckBox_CheckedChanged;
this.pictureBox.Resize += pictureBox_Resize;
this.pictureBox.MouseMove += pictureBox_MouseMove;
this.pictureBox.Paint += pictureBox_Paint;
}
#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)
{
this.carList = new List<Car>();
this.carList.Add(new Car("Audi e-tron" , Color.Red , 69850, 80900, 8.4f, 218, 100f / 44));
this.carList.Add(new Car("Jaguar I-PACE", Color.Green, 39090, 44590, 8.2f, 234, 100f / 30));
this.carList.Add(new Car("Polestar 2" , Color.Blue , 59900, 59900, 8.2f, 275, 100f / 27));
this.axisList = new List<Axis>();
this.axisList.Add(new Axis("PriceLow" , "c" , 90000, 30000));
this.axisList.Add(new Axis("PriceHigh", "c" , 90000, 30000));
this.axisList.Add(new Axis("Rating" , "0.0" , 0 , 10 ));
this.axisList.Add(new Axis("Range" , "0" , 0 , 300 ));
this.axisList.Add(new Axis("Miles/kWh", "0.00", 0 , 5 ));
}
#endregion
#region 영역 채우기 체크 박스 체크 변경시 처리하기 - fillAreaCheckBox_CheckedChanged(sender, e)
/// <summary>
/// 영역 채우기 체크 박스 체크 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void fillAreaCheckBox_CheckedChanged(object sender, EventArgs e)
{
this.pictureBox.Refresh();
}
#endregion
#region 픽처 박스 크기 변경시 처리하기 - pictureBox_Resize(sender, e)
/// <summary>
/// 픽처 박스 크기 변경시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictureBox_Resize(object sender, EventArgs e)
{
this.pictureBox.Refresh();
}
#endregion
#region 픽처 박스 마우스 이동시 처리하기 - pictureBox_MouseMove(sender, e)
/// <summary>
/// 픽처 박스 마우스 이동시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictureBox_MouseMove(object sender, MouseEventArgs e)
{
string tipText = string.Empty;
foreach(Car car in this.carList)
{
if(car.PointArray == null)
{
continue;
}
for(int i = 0; i < car.ValueArray.Length; i++)
{
if(IsPointClose(e.Location, car.PointArray[i], 8))
{
tipText = car.Name + " " +
this.axisList[i].Name + " : " +
car.ValueArray[i].ToString(this.axisList[i].FormatString);
break;
}
if(tipText != string.Empty)
{
break;
}
}
}
if(tipText != this.pointToolTip.GetToolTip(this.pictureBox))
{
this.pointToolTip.SetToolTip(this.pictureBox, tipText);
}
}
#endregion
#region 픽처 박스 페인트시 처리하기 - pictureBox_Paint(sender, e)
/// <summary>
/// 픽처 박스 페인트시 처리하기
/// </summary>
/// <param name="sender">이벤트 발생자</param>
/// <param name="e">이벤트 인자</param>
private void pictureBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
e.Graphics.Clear(this.pictureBox.BackColor);
DrawChart(e.Graphics, this.fillAreaCheckBox.Checked);
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Event
#region 포인트 밀접 여부 구하기 - IsPointClose(point1, point2, radius)
/// <summary>
/// 포인트 밀접 여부 구하기
/// </summary>
/// <param name="point1">포인트 1</param>
/// <param name="point2">포인트 2</param>
/// <param name="radius">반경</param>
/// <returns>포인트 밀접 여부</returns>
private bool IsPointClose(PointF point1, PointF point2, float radius)
{
float deltaX = point1.X - point2.X;
float deltaY = point1.Y - point2.Y;
return (deltaX * deltaX + deltaY * deltaY) < (radius * radius);
}
#endregion
#region 회전된 텍스트 그리기 - DrawRotatedText(graphics, font, brush, text, x, y, theta)
/// <summary>
/// 회전된 텍스트 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="font">폰트</param>
/// <param name="brush">브러시</param>
/// <param name="text">텍스트</param>
/// <param name="x">X</param>
/// <param name="y">Y</param>
/// <param name="theta">세타</param>
private void DrawRotatedText(Graphics graphics, Font font, Brush brush, string text, double x, double y, double theta)
{
GraphicsState state = graphics.Save();
graphics.ResetTransform();
graphics.RotateTransform((float)(theta * 180 / Math.PI));
graphics.TranslateTransform((float)x, (float)y, MatrixOrder.Append);
using(StringFormat stringFormat = new StringFormat())
{
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
graphics.DrawString(text, font, brush, 0, 0, stringFormat);
}
graphics.Restore(state);
}
#endregion
#region 축 그리기 - DrawAxis(graphics, centerX, centerY, radiusX, radiusY, deltaTheta)
/// <summary>
/// 축 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="centerX">중심 X</param>
/// <param name="centerY">중심 Y</param>
/// <param name="radiusX">반경 X</param>
/// <param name="radiusY">반경 Y</param>
/// <param name="deltaTheta">델타 세타</param>
private void DrawAxis(Graphics graphics, float centerX, float centerY, float radiusX, float radiusY, double deltaTheta)
{
double theta = -Math.PI / 2;
using(Font font = new Font("나눔고딕코딩", 12))
{
for(int i = 0; i < this.axisList.Count; i++)
{
double x = centerX + radiusX * Math.Cos(theta);
double y = centerY + radiusY * Math.Sin(theta);
graphics.DrawLine(Pens.Black, centerX, centerY, (float)x, (float)y);
x = centerX + (radiusX + 10) * Math.Cos(theta);
y = centerY + (radiusY + 10) * Math.Sin(theta);
DrawRotatedText
(
graphics,
font,
Brushes.Black,
this.axisList[i].Name,
x,
y,
theta + Math.PI / 2
);
theta += deltaTheta;
}
}
}
#endregion
#region 레벨 그리기 - DrawLevel(graphics, centerX, centerY, radiusX, radiusY, deltaTheta)
/// <summary>
/// 레벨 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="centerX">중심 X</param>
/// <param name="centerY">중심 Y</param>
/// <param name="radiusX">반경 X</param>
/// <param name="radiusY">반경 Y</param>
/// <param name="deltaTheta">델타 세타</param>
private void DrawLevel(Graphics graphics, float centerX, float centerY, float radiusX, float radiusY, double deltaTheta)
{
double theta = -Math.PI / 2;
int levelCount = 5;
double deltaFraction = 1.0 / levelCount;
double fraction = deltaFraction;
PointF[] pointArray = new PointF[this.axisList.Count];
for(int level = 0; level < levelCount; level++)
{
for(int i = 0; i < this.axisList.Count; i++)
{
double x = centerX + fraction * radiusX * Math.Cos(theta);
double y = centerY + fraction * radiusY * Math.Sin(theta);
pointArray[i] = new PointF((float)x, (float)y);
theta += deltaTheta;
}
graphics.DrawPolygon(Pens.Black, pointArray);
fraction += deltaFraction;
}
}
#endregion
#region 레이더 차트 그리기 - DrawRadarChart(car, graphics, fillArea, centerX, centerY, radiusX, radiusY, deltaTheta)
/// <summary>
/// 레이더 차트 그리기
/// </summary>
/// <param name="car">자동차</param>
/// <param name="graphics">그래픽스</param>
/// <param name="fillArea">영역 채우기 여부</param>
/// <param name="centerX">중심 X</param>
/// <param name="centerY">중심 Y</param>
/// <param name="radiusX">반경 X</param>
/// <param name="radiusY">반경 Y</param>
/// <param name="deltaTheta">델타 세타</param>
private void DrawRadarChart
(
Car car,
Graphics graphics,
bool fillArea,
float centerX,
float centerY,
float radiusX,
float radiusY,
double deltaTheta
)
{
PointF[] pointArray = new PointF[this.axisList.Count];
double theta = -Math.PI / 2;
for(int i = 0; i < this.axisList.Count; i++)
{
double fraction = (car.ValueArray[i] - this.axisList[i].Minimum) / (this.axisList[i].Maximum - this.axisList[i].Minimum);
double x = centerX + fraction * radiusX * Math.Cos(theta);
double y = centerY + fraction * radiusY * Math.Sin(theta);
pointArray[i] = new PointF((float)x, (float)y);
theta += deltaTheta;
}
car.PointArray = pointArray;
if(fillArea)
{
Color color = Color.FromArgb(64, car.Color);
using(Brush brush = new SolidBrush(color))
{
graphics.FillPolygon(brush, pointArray);
}
}
using(Pen pen = new Pen(car.Color, 3))
{
graphics.DrawPolygon(pen, pointArray);
}
}
#endregion
#region 레이더 차트 그리기 - DrawRadarChart(graphics, fillArea, centerX, centerY, radiusX, radiusY, deltaTheta)
/// <summary>
/// 레이더 차트 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="fillArea">영역 채우기 여부</param>
/// <param name="centerX">중심 X</param>
/// <param name="centerY">중심 Y</param>
/// <param name="radiusX">반경 X</param>
/// <param name="radiusY">반경 Y</param>
/// <param name="deltaTheta">델타 세타</param>
private void DrawRadarChart
(
Graphics graphics,
bool fillArea,
float centerX,
float centerY,
float radiusX,
float radiusY,
double deltaTheta
)
{
foreach(Car car in this.carList)
{
DrawRadarChart(car, graphics, fillArea, centerX, centerY, radiusX, radiusY, deltaTheta);
}
}
#endregion
#region 차트 그리기 - DrawChart(graphics, fillArea)
/// <summary>
/// 차트 그리기
/// </summary>
/// <param name="graphics">그래픽스</param>
/// <param name="fillArea">영역 채우기</param>
private void DrawChart(Graphics graphics, bool fillArea)
{
float centerX = this.pictureBox.ClientSize.Width / 2f;
float centerY = this.pictureBox.ClientSize.Height / 2f;
float radiusX = centerX - 20;
float radiusY = centerY - 20;
double deltaTheta = 2 * Math.PI / this.axisList.Count;
DrawAxis(graphics, centerX, centerY, radiusX, radiusY, deltaTheta);
DrawLevel(graphics, centerX, centerY, radiusX, radiusY, deltaTheta);
DrawRadarChart(graphics, fillArea, centerX, centerY, radiusX, radiusY, deltaTheta);
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WinForm' 카테고리의 다른 글
[C#/WINFORM] 지정 시간 경과 후 절전 모드에서 활성화하기 (0) | 2020.12.27 |
---|---|
[C#/WINFORM] Graphics 클래스 : DrawImage 메소드 사용시 이미지 어트리뷰트 설정하기 (0) | 2020.12.27 |
[C#/WINFORM] Image 클래스 : 이미지 복사하기 (0) | 2020.12.26 |
[C#/WINFORM] Image 클래스 : 이미지 복사하기 (0) | 2020.12.26 |
[C#/WINFORM] Bitmap 클래스 : 비트맵 픽셀 밝게하기 (0) | 2020.12.26 |
[C#/WINFORM] Graphics 클래스 : DrawString 메소드를 사용해 회전 텍스트 그리기 (0) | 2020.12.26 |
[C#/WINFORM] PointF 구조체 : 포인트 밀접 여부 구하기 (0) | 2020.12.26 |
[C#/WINFORM] RichTextBox 클래스 : 테이블 추가하기 (0) | 2020.12.26 |
[C#/WINFORM] RichTextBox 클래스 : 이미지 캡처하기 (0) | 2020.12.25 |
[C#/WINFORM] Bitmap 클래스 : 합성 이미지 만들기 (0) | 2020.12.25 |
댓글을 달아 주세요