첨부 소스 코드는 나눔고딕코딩 폰트를 사용합니다.
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<RectangleF> circleList = new List<RectangleF>();

        /// <summary>
        /// X1
        /// </summary>
        private int x1;
        
        /// <summary>
        /// Y1
        /// </summary>
        private int y1;
        
        /// <summary>
        /// X2
        /// </summary>
        private int x2;
        
        /// <summary>
        /// Y2
        /// </summary>
        private int y2;

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

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

        /// <summary>
        /// 교차점 수
        /// </summary>
        private int intersectCount = 0;

        #endregion

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

        #region 생성자 - MainForm()

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

            #region 이벤트를 설정한다.

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

            #endregion
        }

        #endregion

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

        #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)
        {
            if(this.circleList.Count == 2)
            {
                this.circleList.Clear();

                this.intersectCount = 0;
            }

            this.x1 = this.x2 = e.X;
            this.y1 = this.y2 = e.Y;

            this.isDrawing = true;
        }

        #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.x2 = e.X;
            this.y2 = 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;

            int width = Math.Min(Math.Abs(this.x1 - this.x2), Math.Abs(this.y1 - this.y2));

            RectangleF rectangle = new RectangleF
            (
                this.x1,
                this.y1,
                width,
                width
            );

            if(this.x1 > this.x2)
            {
                rectangle.X = this.x1 - width;
            }

            if(this.y1 > this.y2)
            {
                rectangle.Y = this.y1 - width;
            }

            this.circleList.Add(rectangle);

            if(this.circleList.Count == 2)
            {
                float radius0 = this.circleList[0].Height / 2;
                float cx0     = this.circleList[0].X + radius0;
                float cy0     = this.circleList[0].Y + radius0;
                float radius1 = this.circleList[1].Height / 2;
                float cx1     = this.circleList[1].X + radius1;
                float cy1     = this.circleList[1].Y + radius1;

                this.intersectCount = FindCircleCircleIntersection
                (
                    cx0,
                    cy0,
                    radius0,
                    cx1,
                    cy1,
                    radius1,
                    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;

            foreach(RectangleF rectangle in this.circleList)
            {
                e.Graphics.DrawEllipse(Pens.Blue, rectangle);
            }

            if(this.isDrawing)
            {
                int width = Math.Min(Math.Abs(this.x1 - this.x2), Math.Abs(this.y1 - this.y2));

                RectangleF rectangle = new RectangleF
                (
                    this.x1,
                    this.y1,
                    width,
                    width
                );

                if(this.x1 > this.x2)
                {
                    rectangle.X = this.x1 - width;
                }

                if(this.y1 > this.y2)
                {
                    rectangle.Y = this.y1 - width;
                }

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

            if(this.intersectCount >= 1)
            {
                DrawPoint(e.Graphics, this.intersectPoint1, Brushes.HotPink, Pens.Red);
            }

            if(this.intersectCount >= 2)
            {
                DrawPoint(e.Graphics, this.intersectPoint2, Brushes.HotPink, Pens.Red);
            }
        }

        #endregion

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

        #region 원/원 교차점 찾기 - FindCircleCircleIntersection(centerX1, centerY1, radius1, centerX2, centerY2, radius2, intersectPoint1, intersectPoint2)

        /// <summary>
        /// 원/원 교차점 찾기
        /// </summary>
        /// <param name="centerX1">원 1 중심점 X</param>
        /// <param name="centerY1">원 1 중심점 Y</param>
        /// <param name="radius1">원 1 반경</param>
        /// <param name="centerX2">원 2 중심 X</param>
        /// <param name="centerY2">원 2 중심 Y</param>
        /// <param name="radius2">원 2 반경</param>
        /// <param name="intersectPoint1">교차점 1</param>
        /// <param name="intersectPoint2">교차점 2</param>
        /// <returns>교차 수</returns>
        private int FindCircleCircleIntersection(float centerX1, float centerY1, float radius1, float centerX2, float centerY2, float radius2,
            out PointF intersectPoint1, out PointF intersectPoint2)
        {
            float  deltaX   = centerX1 - centerX2;
            float  deltaY   = centerY1 - centerY2;
            double distance = Math.Sqrt(deltaX * deltaX + deltaY * deltaY);

            if(distance > radius1 + radius2)
            {
                intersectPoint1 = new PointF(float.NaN, float.NaN);
                intersectPoint2 = new PointF(float.NaN, float.NaN);

                return 0;
            }
            else if(distance < Math.Abs(radius1 - radius2))
            {
                intersectPoint1 = new PointF(float.NaN, float.NaN);
                intersectPoint2 = new PointF(float.NaN, float.NaN);

                return 0;
            }
            else if((distance == 0) && (radius1 == radius2))
            {
                intersectPoint1 = new PointF(float.NaN, float.NaN);
                intersectPoint2 = new PointF(float.NaN, float.NaN);

                return 0;
            }
            else
            {
                double a = (radius1 * radius1 - radius2 * radius2 + distance * distance) / (2 * distance);
                double h = Math.Sqrt(radius1 * radius1 - a * a);

                double centaX3 = centerX1 + a * (centerX2 - centerX1) / distance;
                double centaY3 = centerY1 + a * (centerY2 - centerY1) / distance;
 
                intersectPoint1 = new PointF
                (
                    (float)(centaX3 + h * (centerY2 - centerY1) / distance),
                    (float)(centaY3 - h * (centerX2 - centerX1) / distance)
                );

                intersectPoint2 = new PointF
                (
                    (float)(centaX3 - h * (centerY2 - centerY1) / distance),
                    (float)(centaY3 + h * (centerX2 - centerX1) / distance)
                );

                if(distance == radius1 + radius2)
                {
                    return 1;
                }

                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

댓글을 달아 주세요