첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.

728x90
반응형
728x170

TestProject.zip
다운로드

▶ 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>
        /// 포인트 리스트
        /// </summary>
        private List<Point> pointList = new List<Point>();

        /// <summary>
        /// 그리기 여부
        /// </summary>
        private bool isDrawing = false;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainForm()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            this.alternateRadioButton.Click += radioButton_Click;
            this.windingRadioButton.Click   += radioButton_Click;
            this.pictureBox.MouseClick      += pictureBox_MouseClick;
            this.pictureBox.Paint           += pictureBox_Paint;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 라디오 버튼 클릭시 처리하기 - radioButton_Click(sender, e)

        /// <summary>
        /// 라디오 버튼 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void radioButton_Click(object sender, EventArgs e)
        {
            this.pictureBox.Refresh();
        }

        #endregion
        #region 픽처 박스 마우스 클릭시 처리하기 - pictureBox_MouseClick(sender, e)

        /// <summary>
        /// 픽처 박스 마우스 클릭시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void pictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Left)
            {
                if(!this.isDrawing)
                {
                    this.pointList = new List<Point>();

                    this.isDrawing = true;
                }

                this.pointList.Add(e.Location);
            }
            else
            {
                this.isDrawing = false;
            }

            this.pictureBox.Refresh();
        }

        #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.Clear(pictureBox.BackColor);

            if(this.isDrawing)
            {
                if(this.pointList.Count > 1)
                {
                    e.Graphics.DrawLines(Pens.Blue, this.pointList.ToArray());
                }

                DrawLineArrow(e.Graphics, Pens.Blue, this.pointList, this.pointList.Count - 1);
            }
            else
            {
                if(this.pointList.Count > 2)
                {
                    FillMode fillMode;

                    if(windingRadioButton.Checked)
                    {
                        fillMode = FillMode.Winding;
                    }
                    else
                    {
                        fillMode = FillMode.Alternate;
                    }

                    e.Graphics.FillPolygon(Brushes.LightBlue, this.pointList.ToArray(), fillMode);

                    e.Graphics.DrawPolygon(Pens.Blue, this.pointList.ToArray());
                }

                DrawLineArrow(e.Graphics, Pens.Blue, this.pointList, this.pointList.Count);
            }

            foreach(Point point in this.pointList)
            {
                DrawDot(e.Graphics, Brushes.White, Pens.Black, point);
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 화살표 헤더 그리기 - DrawArrowHead(graphics, pen, point1, point2)

        /// <summary>
        /// 화살표 헤더 그리기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="pen">펜</param>
        /// <param name="point1">포인트 1</param>
        /// <param name="point2">포인트 2</param>
        private void DrawArrowHead(Graphics graphics, Pen pen, Point point1, Point point2)
        {
            float deltaX = point2.X - point1.X;
            float deltaY = point2.Y - point1.Y;

            float distance = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);

            deltaX /= distance;
            deltaY /= distance;

            const float scale = 4;

            deltaX *= scale;
            deltaY *= scale;

            float pointX1 = -deltaY;
            float pointY1 =  deltaX;
            float pointX2 =  deltaY;
            float pointY2 = -deltaX;

            float centerX = (point1.X + point2.X) / 2f;
            float centerY = (point1.Y + point2.Y) / 2f;

            PointF[] pointArray =
            {
                new PointF(centerX - deltaX + pointX1, centerY - deltaY + pointY1),
                new PointF(centerX                   , centerY                   ),
                new PointF(centerX - deltaX + pointX2, centerY - deltaY + pointY2)
            };

            graphics.DrawLines(pen, pointArray);
        }
        
        #endregion
        #region 화살표 선 그리기 - DrawLineArrow(graphics, pen, pointList, segmentCount)

        /// <summary>
        /// 화살표 선 그리기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="pen">펜</param>
        /// <param name="pointList">포인트 리스트</param>
        /// <param name="segmentCount">세그먼트 수</param>
        private void DrawLineArrow(Graphics graphics, Pen pen, List<Point> pointList, int segmentCount)
        {
            for(int i = 0; i < segmentCount; i++)
            {
                int j = (i + 1) % pointList.Count;

                DrawArrowHead(graphics, pen, pointList[i], pointList[j]);
            }
        }

        #endregion
        #region 점 그리기 - DrawDot(graphics, brush, pen, point)

        /// <summary>
        /// 점 그리기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="brush">브러시</param>
        /// <param name="pen">펜</param>
        /// <param name="point">포인트</param>
        private void DrawDot(Graphics graphics, Brush brush, Pen pen, PointF point)
        {
            const float radius = 3;

            RectangleF rectf = new RectangleF
            (
                point.X - radius,
                point.Y - radius,
                2 * radius,
                2 * radius
            );

            graphics.FillEllipse(brush, rectf);

            graphics.DrawEllipse(pen, rectf);
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요