첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
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 const int Radius = 4;

        /// <summary>
        /// 포인트 리스트
        /// </summary>
        private List<PointF> pointList = new List<PointF>();

        #endregion

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

        #region 생성자 - MainForm()

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

            this.pictureBox.MouseClick += pictureBox_MouseClick;
            this.pictureBox.Paint      += pictureBox_Paint;
        }

        #endregion

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

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

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

            this.pointList.Add(e.Location);

            this.pictureBox.Refresh();

            if(this.pointList.Count == 3)
            {
                double radian = GetVectorAngle
                (
                    this.pointList[0], this.pointList[1],
                    this.pointList[1], this.pointList[2]
                );

                double degree = radian / Math.PI * 180;

                this.angleLabel.Text = $"라디안 : {radian.ToString("0.00")}, 각도 : {degree.ToString("0.00")}";
            }
            else
            {
                this.angleLabel.Text = "";
            }
        }

        #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;

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

                for(int i = 1; i < this.pointList.Count; i++)
                {
                    DrawArrowHead(e.Graphics, Pens.Red, Radius, this.pointList[i - 1], this.pointList[i]);
                }
            }

            foreach(PointF point in this.pointList)
            {
                RectangleF rectangle = new RectangleF
                (
                    point.X - Radius,
                    point.Y - Radius,
                    2 * Radius,
                    2 * Radius
                );

                e.Graphics.FillEllipse(Brushes.LightBlue, rectangle);

                e.Graphics.DrawEllipse(Pens.Blue, rectangle);
            }
        }

        #endregion

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

        #region 벡터 각도 구하기 - GetVectorAngle(startPoint1, endPoint1, startPoint2, endPoint2)

        /// <summary>
        /// 벡터 각도 구하기
        /// </summary>
        /// <param name="startPoint1">시작 포인트 1</param>
        /// <param name="endPoint1">종료 포인트 1</param>
        /// <param name="startPoint2">시작 포인트 2</param>
        /// <param name="endPoint2">종료 포인트 2</param>
        /// <returns>벡터 각도</returns>
        private double GetVectorAngle(PointF startPoint1, PointF endPoint1, PointF startPoint2, PointF endPoint2)
        {
            PointF vector1 = new PointF(endPoint1.X - startPoint1.X, endPoint1.Y - startPoint1.Y);
            PointF vector2 = new PointF(endPoint2.X - startPoint2.X, endPoint2.Y - startPoint2.Y);

            double length1 = Math.Sqrt(vector1.X * vector1.X + vector1.Y * vector1.Y);
            double length2 = Math.Sqrt(vector2.X * vector2.X + vector2.Y * vector2.Y);

            double dotProduct = vector1.X * vector2.X + vector1.Y * vector2.Y;
            double cosine     = dotProduct / length1 / length2;

            double crossProduct = vector1.X * vector2.Y - vector1.Y * vector2.X;
            double sine         = crossProduct / length1 / length2;

            double angle = Math.Acos(cosine);

            if(sine < 0)
            {
                angle = -angle;
            }

            return angle;
        }

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

        /// <summary>
        /// 화살표 헤더 그리기
        /// </summary>
        /// <param name="graphics">그래픽스</param>
        /// <param name="pen">펜</param>
        /// <param name="radius">반경</param>
        /// <param name="point1">포인트 1</param>
        /// <param name="point2">포인트 2</param>
        private void DrawArrowHead(Graphics graphics, Pen pen, float radius, PointF point1, PointF 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;

            float unitVectorX = deltaX;
            float unitVectorY = deltaY;

            const float scale = 6;

            deltaX *= scale;
            deltaY *= scale;

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

            float centerX = point2.X - unitVectorX * radius;
            float centerY = point2.Y - unitVectorY * radius;

            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
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요