첨부 소스 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

TestProject.zip
다운로드

▶ MainForm.cs

using System;
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 float circleCenterX;
        
        /// <summary>
        /// 원 중심점 Y
        /// </summary>
        private float circleCenterY;
        
        /// <summary>
        /// 원 반경
        /// </summary>
        private float circleRadius;

        /// <summary>
        /// 직선 포인트 1
        /// </summary>
        private PointF linePoint1;
        
        /// <summary>
        /// 직선 포인트 2
        /// </summary>
        private PointF linePoint2;

        /// <summary>
        /// 그리기 여부
        /// </summary>
        private bool isDrawing = false;
        
        /// <summary>
        /// 포인트 보유 여부
        /// </summary>
        private bool havePoints = false;

        /// <summary>
        /// 교차점 1
        /// </summary>
        private PointF intersectPoint1;
        
        /// <summary>
        /// 교차점 2
        /// </summary>
        private PointF intersectPoint2;

        /// <summary>
        /// 교차 수
        /// </summary>
        private int intersectCount;

        #endregion

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

        #region 생성자 - MainForm()

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

            ResizeRedraw = true;

            InitializeCircle();

            #region 이벤트를 설정한다.

            Resize    += Form_Resize;
            MouseDown += Form_MouseDown;
            MouseMove += Form_MouseMove;
            MouseUp   += Form_MouseUp;
            Paint     += Form_Paint;

            #endregion
        }

        #endregion

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

        #region 폼 크기 조정시 처리하기 - Form_Resize(sender, e)

        /// <summary>
        /// 폼 크기 조정시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_Resize(object sender, EventArgs e)
        {
            this.intersectCount = 0;

            this.havePoints = false;

            InitializeCircle();
        }

        #endregion
        #region 폼 마우스 DOWN 처리하기 - Form_MouseDown(sender, e)

        /// <summary>
        /// 폼 마우스 DOWN 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_MouseDown(object sender, MouseEventArgs e)
        {
            this.isDrawing = true;

            this.intersectCount = 0;

            this.linePoint1 = new PointF(e.X, e.Y);
            this.linePoint2 = new PointF(e.X, e.Y);

            this.havePoints = true;

            Invalidate();
        }

        #endregion
        #region 폼 마우스 이동시 처리하기 - Form_MouseMove(sender, e)

        /// <summary>
        /// 폼 마우스 이동시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_MouseMove(object sender, MouseEventArgs e)
        {
            if(!this.isDrawing)
            {
                return;
            }

            this.linePoint2 = new PointF(e.X, e.Y);

            Invalidate();
        }

        #endregion
        #region 폼 마우스 UP 처리하기 - Form_MouseUp(sender, e)

        /// <summary>
        /// 폼 마우스 UP 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_MouseUp(object sender, MouseEventArgs e)
        {
            this.isDrawing = false;

            this.intersectCount = FindLineCircleIntersection
            (
                this.circleCenterX,
                this.circleCenterY,
                this.circleRadius,
                this.linePoint1,
                this.linePoint2,
                out this.intersectPoint1,
                out this.intersectPoint2
            );

            Invalidate();
        }

        #endregion
        #region 폼 페인트시 처리하기 - Form_Paint(sender, e)

        /// <summary>
        /// 폼 페인트시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void Form_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            e.Graphics.DrawEllipse
            (
                Pens.Blue, 
                this.circleCenterX - this.circleRadius,
                this.circleCenterY - this.circleRadius,
                this.circleRadius * 2,
                this.circleRadius * 2
            );

            if(this.havePoints && this.intersectCount > 0)
            {
                using(Pen pen = new Pen(Color.Red))
                {
                    pen.DashPattern = new float[] { 3, 3 };

                    e.Graphics.DrawLine(pen, this.intersectPoint1, this.linePoint1);
                }
            }

            switch(this.intersectCount)
            {
                case 0 :

                    break;

                case 1 :

                    DrawPoint(e.Graphics, this.intersectPoint1, Brushes.HotPink, Pens.Red);

                    break;

                case 2 :

                    DrawPoint(e.Graphics, this.intersectPoint1, Brushes.HotPink, Pens.Red);
                    DrawPoint(e.Graphics, this.intersectPoint2, Brushes.HotPink, Pens.Red);

                    break;
            }

            if(this.havePoints)
            {
                DrawPoint(e.Graphics, this.linePoint1, Brushes.White, Pens.Black);
                DrawPoint(e.Graphics, this.linePoint2, Brushes.White, Pens.Black);

                e.Graphics.DrawLine(Pens.BlueViolet, this.linePoint1, this.linePoint2);
            }
        }

        #endregion

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

        #region 원 초기화 하기 - InitializeCircle()

        /// <summary>
        /// 원 초기화 하기
        /// </summary>
        private void InitializeCircle()
        {
            this.circleCenterX = ClientSize.Width  / 2;
            this.circleCenterY = ClientSize.Height / 2;
            this.circleRadius  = (float)(Math.Min(this.circleCenterX, this.circleCenterY) * 0.8);

            this.havePoints = false;

            Invalidate();
        }

        #endregion
        #region 직선/원 교차점 찾기 - FindLineCircleIntersection(circleCenterX, circleCenterY, circleRadius, linePoint1, linePoint2, intersectPoint1, intersectPoint2)

        /// <summary>
        /// 직선/원 교차점 찾기
        /// </summary>
        /// <param name="circleCenterX">원 중심점 X</param>
        /// <param name="circleCenterY">원 중심점 Y</param>
        /// <param name="circleRadius">원 반경</param>
        /// <param name="linePoint1">직선 포인트 1</param>
        /// <param name="linePoint2">직선 포인트 2</param>
        /// <param name="intersectPoint1">교차점 1</param>
        /// <param name="intersectPoint2">교차점 2</param>
        /// <returns>교차점 수</returns>
        private int FindLineCircleIntersection(float circleCenterX, float circleCenterY, float circleRadius, PointF linePoint1, PointF linePoint2,
            out PointF intersectPoint1, out PointF intersectPoint2)
        {
            float deltaX;
            float deltaY;
            float a;
            float b;
            float c;
            float det;
            float t;

            deltaX = linePoint2.X - linePoint1.X;
            deltaY = linePoint2.Y - linePoint1.Y;

            a = deltaX * deltaX + deltaY * deltaY;
            b = 2 * (deltaX * (linePoint1.X - circleCenterX) + deltaY * (linePoint1.Y - circleCenterY));
            c = (linePoint1.X - circleCenterX) * (linePoint1.X - circleCenterX) + (linePoint1.Y - circleCenterY) * (linePoint1.Y - circleCenterY) - circleRadius * circleRadius;

            det = b * b - 4 * a * c;

            if((a <= 0.0000001) || (det < 0))
            {
                intersectPoint1 = new PointF(float.NaN, float.NaN);
                intersectPoint2 = new PointF(float.NaN, float.NaN);

                return 0;
            }
            else if(det == 0)
            {
                t = -b / (2 * a);

                intersectPoint1 = new PointF(linePoint1.X + t * deltaX, linePoint1.Y + t * deltaY);
                intersectPoint2 = new PointF(float.NaN, float.NaN);

                return 1;
            }
            else
            {
                t = (float)((-b + Math.Sqrt(det)) / (2 * a));

                intersectPoint1 = new PointF(linePoint1.X + t * deltaX, linePoint1.Y + t * deltaY);

                t = (float)((-b - Math.Sqrt(det)) / (2 * a));

                intersectPoint2 = new PointF(linePoint1.X + t * deltaX, linePoint1.Y + t * deltaY);

                return 2;
            }
        }

        #endregion
        #region 포인트 그리기 - DrawPoint(graphics, point, brush, pen)

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

            graphics.FillEllipse
            (
                brush,
                point.X - RADIUS,
                point.Y - RADIUS,
                2 * RADIUS,
                2 * RADIUS
            );

            graphics.DrawEllipse
            (
                pen,
                point.X - RADIUS,
                point.Y - RADIUS,
                2 * RADIUS,
                2 * RADIUS
            );
        }

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

댓글을 달아 주세요