첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

728x90
반응형

■ 직선과 원의 교차 여부 구하기

------------------------------------------------------------------------------------------------------------------------


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

댓글을 달아 주세요